1 : /******************************************************************************
2 : * $Id: pdfcreatecopy.cpp 24189 2012-04-01 14:20:02Z rouault $
3 : *
4 : * Project: PDF driver
5 : * Purpose: GDALDataset driver for PDF dataset.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2012, Even Rouault
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : /* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef bool GBool" */
31 : /* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
32 : #define CPL_GBOOL_DEFINED
33 :
34 : #include "pdfcreatecopy.h"
35 :
36 : #include "cpl_vsi_virtual.h"
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 : #include "ogr_spatialref.h"
40 : #include "ogr_geometry.h"
41 : #include "vrt/vrtdataset.h"
42 :
43 : #include "pdfobject.h"
44 :
45 : #ifndef M_PI
46 : #define M_PI 3.14159265358979323846
47 : #endif
48 :
49 : CPL_CVSID("$Id: pdfcreatecopy.cpp 24189 2012-04-01 14:20:02Z rouault $");
50 :
51 : #define PIXEL_TO_GEO_X(x,y) adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2]
52 : #define PIXEL_TO_GEO_Y(x,y) adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5]
53 :
54 : class GDALFakePDFDataset : public GDALDataset
55 : {
56 : public:
57 : GDALFakePDFDataset() {}
58 : };
59 :
60 : /************************************************************************/
61 : /* Init() */
62 : /************************************************************************/
63 :
64 142 : void GDALPDFWriter::Init()
65 : {
66 142 : nPageResourceId = 0;
67 142 : nStructTreeRootId = 0;
68 142 : nCatalogId = nCatalogGen = 0;
69 142 : bInWriteObj = FALSE;
70 142 : nInfoId = nInfoGen = 0;
71 142 : nXMPId = nXMPGen = 0;
72 :
73 142 : nLastStartXRef = 0;
74 142 : nLastXRefSize = 0;
75 142 : bCanUpdate = FALSE;
76 142 : }
77 :
78 : /************************************************************************/
79 : /* GDALPDFWriter() */
80 : /************************************************************************/
81 :
82 142 : GDALPDFWriter::GDALPDFWriter(VSILFILE* fpIn, int bAppend) : fp(fpIn)
83 : {
84 142 : Init();
85 :
86 142 : if (!bAppend)
87 : {
88 92 : VSIFPrintfL(fp, "%%PDF-1.6\n");
89 :
90 : /* See PDF 1.7 reference, page 92. Write 4 non-ASCII bytes to indicate that the content will be binary */
91 92 : VSIFPrintfL(fp, "%%%c%c%c%c\n", 0xFF, 0xFF, 0xFF, 0xFF);
92 :
93 92 : nPageResourceId = AllocNewObject();
94 92 : nCatalogId = AllocNewObject();
95 : }
96 142 : }
97 :
98 : /************************************************************************/
99 : /* ~GDALPDFWriter() */
100 : /************************************************************************/
101 :
102 142 : GDALPDFWriter::~GDALPDFWriter()
103 : {
104 142 : Close();
105 142 : }
106 :
107 : /************************************************************************/
108 : /* ParseIndirectRef() */
109 : /************************************************************************/
110 :
111 58 : static int ParseIndirectRef(const char* pszStr, int& nNum, int &nGen)
112 : {
113 116 : while(*pszStr == ' ')
114 0 : pszStr ++;
115 :
116 58 : nNum = atoi(pszStr);
117 182 : while(*pszStr >= '0' && *pszStr <= '9')
118 66 : pszStr ++;
119 58 : if (*pszStr != ' ')
120 0 : return FALSE;
121 :
122 174 : while(*pszStr == ' ')
123 58 : pszStr ++;
124 :
125 58 : nGen = atoi(pszStr);
126 174 : while(*pszStr >= '0' && *pszStr <= '9')
127 58 : pszStr ++;
128 58 : if (*pszStr != ' ')
129 0 : return FALSE;
130 :
131 174 : while(*pszStr == ' ')
132 58 : pszStr ++;
133 :
134 58 : return *pszStr == 'R';
135 : }
136 :
137 : /************************************************************************/
138 : /* ParseTrailerAndXRef() */
139 : /************************************************************************/
140 :
141 50 : int GDALPDFWriter::ParseTrailerAndXRef()
142 : {
143 50 : VSIFSeekL(fp, 0, SEEK_END);
144 : char szBuf[1024+1];
145 50 : vsi_l_offset nOffset = VSIFTellL(fp);
146 :
147 50 : if (nOffset > 128)
148 50 : nOffset -= 128;
149 : else
150 0 : nOffset = 0;
151 :
152 : /* Find startxref section */
153 50 : VSIFSeekL(fp, nOffset, SEEK_SET);
154 50 : int nRead = VSIFReadL(szBuf, 1, 128, fp);
155 50 : szBuf[nRead] = 0;
156 50 : if (nRead < 9)
157 0 : return FALSE;
158 :
159 50 : const char* pszStartXRef = NULL;
160 : int i;
161 646 : for(i = nRead - 9; i>= 0; i --)
162 : {
163 646 : if (strncmp(szBuf + i, "startxref", 9) == 0)
164 : {
165 50 : pszStartXRef = szBuf + i;
166 50 : break;
167 : }
168 : }
169 50 : if (pszStartXRef == NULL)
170 : {
171 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find startxref");
172 0 : return FALSE;
173 : }
174 50 : pszStartXRef += 9;
175 150 : while(*pszStartXRef == '\r' || *pszStartXRef == '\n')
176 50 : pszStartXRef ++;
177 50 : if (*pszStartXRef == '\0')
178 : {
179 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find startxref");
180 0 : return FALSE;
181 : }
182 :
183 50 : nLastStartXRef = atoi(pszStartXRef);
184 :
185 : /* Skip to beginning of xref section */
186 50 : VSIFSeekL(fp, nLastStartXRef, SEEK_SET);
187 :
188 : /* And skip to trailer */
189 : const char* pszLine;
190 50 : while( (pszLine = CPLReadLineL(fp)) != NULL)
191 : {
192 522 : if (strncmp(pszLine, "trailer", 7) == 0)
193 50 : break;
194 : }
195 :
196 50 : if( pszLine == NULL )
197 : {
198 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find trailer");
199 0 : return FALSE;
200 : }
201 :
202 : /* Read trailer content */
203 50 : nRead = VSIFReadL(szBuf, 1, 1024, fp);
204 50 : szBuf[nRead] = 0;
205 :
206 : /* Find XRef size */
207 50 : const char* pszSize = strstr(szBuf, "/Size");
208 50 : if (pszSize == NULL)
209 : {
210 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find trailer /Size");
211 0 : return FALSE;
212 : }
213 50 : pszSize += 5;
214 150 : while(*pszSize == ' ')
215 50 : pszSize ++;
216 50 : nLastXRefSize = atoi(pszSize);
217 :
218 : /* Find Root object */
219 50 : const char* pszRoot = strstr(szBuf, "/Root");
220 50 : if (pszRoot == NULL)
221 : {
222 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot find trailer /Root");
223 0 : return FALSE;
224 : }
225 50 : pszRoot += 5;
226 150 : while(*pszRoot == ' ')
227 50 : pszRoot ++;
228 :
229 50 : if (!ParseIndirectRef(pszRoot, nCatalogId, nCatalogGen))
230 : {
231 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot parse trailer /Root");
232 0 : return FALSE;
233 : }
234 :
235 : /* Find Info object */
236 50 : const char* pszInfo = strstr(szBuf, "/Info");
237 50 : if (pszInfo != NULL)
238 : {
239 8 : pszInfo += 5;
240 24 : while(*pszInfo == ' ')
241 8 : pszInfo ++;
242 :
243 8 : if (!ParseIndirectRef(pszInfo, nInfoId, nInfoGen))
244 : {
245 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot parse trailer /Info");
246 0 : nInfoId = nInfoGen = 0;
247 : }
248 : }
249 :
250 50 : VSIFSeekL(fp, 0, SEEK_END);
251 :
252 50 : return TRUE;
253 : }
254 :
255 : /************************************************************************/
256 : /* Close() */
257 : /************************************************************************/
258 :
259 284 : void GDALPDFWriter::Close()
260 : {
261 284 : if (fp)
262 : {
263 142 : CPLAssert(!bInWriteObj);
264 142 : if (nPageResourceId)
265 : {
266 92 : WritePages();
267 92 : WriteXRefTableAndTrailer();
268 : }
269 50 : else if (bCanUpdate)
270 : {
271 44 : WriteXRefTableAndTrailer();
272 : }
273 142 : VSIFCloseL(fp);
274 : }
275 284 : fp = NULL;
276 284 : }
277 :
278 : /************************************************************************/
279 : /* UpdateProj() */
280 : /************************************************************************/
281 :
282 20 : void GDALPDFWriter::UpdateProj(GDALDataset* poSrcDS,
283 : double dfDPI,
284 : GDALPDFDictionaryRW* poPageDict,
285 : int nPageNum, int nPageGen)
286 : {
287 20 : bCanUpdate = TRUE;
288 20 : if ((int)asXRefEntries.size() < nLastXRefSize - 1)
289 20 : asXRefEntries.resize(nLastXRefSize - 1);
290 :
291 20 : int nViewportId = 0;
292 20 : int nLGIDictId = 0;
293 :
294 20 : CPLAssert(nPageNum != 0);
295 20 : CPLAssert(poPageDict != NULL);
296 :
297 20 : PDFMargins sMargins = {0, 0, 0, 0};
298 :
299 20 : const char* pszGEO_ENCODING = CPLGetConfigOption("GDAL_PDF_GEO_ENCODING", "ISO32000");
300 20 : if (EQUAL(pszGEO_ENCODING, "ISO32000") || EQUAL(pszGEO_ENCODING, "BOTH"))
301 18 : nViewportId = WriteSRS_ISO32000(poSrcDS, dfDPI / 72.0, NULL, &sMargins);
302 20 : if (EQUAL(pszGEO_ENCODING, "OGC_BP") || EQUAL(pszGEO_ENCODING, "BOTH"))
303 2 : nLGIDictId = WriteSRS_OGC_BP(poSrcDS, dfDPI / 72.0, NULL, &sMargins);
304 :
305 : #ifdef invalidate_xref_entry
306 : GDALPDFObject* poVP = poPageDict->Get("VP");
307 : if (poVP)
308 : {
309 : if (poVP->GetType() == PDFObjectType_Array &&
310 : poVP->GetArray()->GetLength() == 1)
311 : poVP = poVP->GetArray()->Get(0);
312 :
313 : int nVPId = poVP->GetRefNum();
314 : if (nVPId)
315 : {
316 : asXRefEntries[nVPId - 1].bFree = TRUE;
317 : asXRefEntries[nVPId - 1].nGen ++;
318 : }
319 : }
320 : #endif
321 :
322 20 : poPageDict->Remove("VP");
323 20 : poPageDict->Remove("LGIDict");
324 :
325 20 : if (nViewportId)
326 : {
327 : poPageDict->Add("VP", &((new GDALPDFArrayRW())->
328 14 : Add(nViewportId, 0)));
329 : }
330 :
331 20 : if (nLGIDictId)
332 : {
333 2 : poPageDict->Add("LGIDict", nLGIDictId, 0);
334 : }
335 :
336 20 : StartObj(nPageNum, nPageGen);
337 20 : VSIFPrintfL(fp, "%s\n", poPageDict->Serialize().c_str());
338 20 : EndObj();
339 20 : }
340 :
341 : /************************************************************************/
342 : /* UpdateInfo() */
343 : /************************************************************************/
344 :
345 12 : void GDALPDFWriter::UpdateInfo(GDALDataset* poSrcDS)
346 : {
347 12 : bCanUpdate = TRUE;
348 12 : if ((int)asXRefEntries.size() < nLastXRefSize - 1)
349 12 : asXRefEntries.resize(nLastXRefSize - 1);
350 :
351 12 : int nNewInfoId = SetInfo(poSrcDS, NULL);
352 : /* Write empty info, because podofo driver will find the dangling info instead */
353 12 : if (nNewInfoId == 0 && nInfoId != 0)
354 : {
355 : #ifdef invalidate_xref_entry
356 : asXRefEntries[nInfoId - 1].bFree = TRUE;
357 : asXRefEntries[nInfoId - 1].nGen ++;
358 : #else
359 4 : StartObj(nInfoId, nInfoGen);
360 4 : VSIFPrintfL(fp, "<< >>\n");
361 4 : EndObj();
362 : #endif
363 : }
364 12 : }
365 :
366 : /************************************************************************/
367 : /* UpdateXMP() */
368 : /************************************************************************/
369 :
370 12 : void GDALPDFWriter::UpdateXMP(GDALDataset* poSrcDS,
371 : GDALPDFDictionaryRW* poCatalogDict)
372 : {
373 12 : bCanUpdate = TRUE;
374 12 : if ((int)asXRefEntries.size() < nLastXRefSize - 1)
375 12 : asXRefEntries.resize(nLastXRefSize - 1);
376 :
377 12 : CPLAssert(nCatalogId != 0);
378 12 : CPLAssert(poCatalogDict != NULL);
379 :
380 12 : GDALPDFObject* poMetadata = poCatalogDict->Get("Metadata");
381 12 : if (poMetadata)
382 : {
383 8 : nXMPId = poMetadata->GetRefNum();
384 8 : nXMPGen = poMetadata->GetRefGen();
385 : }
386 :
387 12 : poCatalogDict->Remove("Metadata");
388 12 : int nNewXMPId = SetXMP(poSrcDS, NULL);
389 :
390 : /* Write empty metadata, because podofo driver will find the dangling info instead */
391 12 : if (nNewXMPId == 0 && nXMPId != 0)
392 : {
393 4 : StartObj(nXMPId, nXMPGen);
394 4 : VSIFPrintfL(fp, "<< >>\n");
395 4 : EndObj();
396 : }
397 :
398 12 : if (nXMPId)
399 12 : poCatalogDict->Add("Metadata", nXMPId, 0);
400 :
401 12 : StartObj(nCatalogId, nCatalogGen);
402 12 : VSIFPrintfL(fp, "%s\n", poCatalogDict->Serialize().c_str());
403 12 : EndObj();
404 12 : }
405 :
406 : /************************************************************************/
407 : /* AllocNewObject() */
408 : /************************************************************************/
409 :
410 1162 : int GDALPDFWriter::AllocNewObject()
411 : {
412 1162 : asXRefEntries.push_back(GDALXRefEntry());
413 1162 : return (int)asXRefEntries.size();
414 : }
415 :
416 : /************************************************************************/
417 : /* WriteXRefTableAndTrailer() */
418 : /************************************************************************/
419 :
420 136 : void GDALPDFWriter::WriteXRefTableAndTrailer()
421 : {
422 136 : vsi_l_offset nOffsetXREF = VSIFTellL(fp);
423 136 : VSIFPrintfL(fp, "xref\n");
424 :
425 : char buffer[16];
426 136 : if (bCanUpdate)
427 : {
428 44 : VSIFPrintfL(fp, "0 1\n");
429 44 : VSIFPrintfL(fp, "0000000000 65535 f \n");
430 620 : for(size_t i=0;i<asXRefEntries.size();)
431 : {
432 532 : if (asXRefEntries[i].nOffset != 0 || asXRefEntries[i].bFree)
433 : {
434 : /* Find number of consecutive objects */
435 72 : size_t nCount = 1;
436 172 : while(i + nCount <asXRefEntries.size() &&
437 : (asXRefEntries[i + nCount].nOffset != 0 || asXRefEntries[i + nCount].bFree))
438 28 : nCount ++;
439 :
440 72 : VSIFPrintfL(fp, "%d %d\n", (int)i + 1, (int)nCount);
441 72 : size_t iEnd = i + nCount;
442 172 : for(; i < iEnd; i++)
443 : {
444 100 : snprintf (buffer, sizeof(buffer), "%010ld", (long)asXRefEntries[i].nOffset);
445 : VSIFPrintfL(fp, "%s %05d %c \n",
446 : buffer, asXRefEntries[i].nGen,
447 100 : asXRefEntries[i].bFree ? 'f' : 'n');
448 : }
449 : }
450 : else
451 : {
452 460 : i++;
453 : }
454 : }
455 : }
456 : else
457 : {
458 : VSIFPrintfL(fp, "%d %d\n",
459 92 : 0, (int)asXRefEntries.size() + 1);
460 92 : VSIFPrintfL(fp, "0000000000 65535 f \n");
461 1202 : for(size_t i=0;i<asXRefEntries.size();i++)
462 : {
463 1110 : snprintf (buffer, sizeof(buffer), "%010ld", (long)asXRefEntries[i].nOffset);
464 1110 : VSIFPrintfL(fp, "%s %05d n \n", buffer, asXRefEntries[i].nGen);
465 : }
466 : }
467 :
468 136 : VSIFPrintfL(fp, "trailer\n");
469 136 : GDALPDFDictionaryRW oDict;
470 : oDict.Add("Size", (int)asXRefEntries.size() + 1)
471 136 : .Add("Root", nCatalogId, nCatalogGen);
472 136 : if (nInfoId)
473 16 : oDict.Add("Info", nInfoId, nInfoGen);
474 136 : if (nLastStartXRef)
475 44 : oDict.Add("Prev", nLastStartXRef);
476 136 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
477 :
478 : VSIFPrintfL(fp,
479 : "startxref\n"
480 : "%ld\n"
481 : "%%%%EOF\n",
482 136 : (long)nOffsetXREF);
483 136 : }
484 :
485 : /************************************************************************/
486 : /* StartObj() */
487 : /************************************************************************/
488 :
489 1210 : void GDALPDFWriter::StartObj(int nObjectId, int nGen)
490 : {
491 1210 : CPLAssert(!bInWriteObj);
492 1210 : CPLAssert(nObjectId - 1 < (int)asXRefEntries.size());
493 1210 : CPLAssert(asXRefEntries[nObjectId - 1].nOffset == 0);
494 1210 : asXRefEntries[nObjectId - 1].nOffset = VSIFTellL(fp);
495 1210 : asXRefEntries[nObjectId - 1].nGen = nGen;
496 1210 : VSIFPrintfL(fp, "%d %d obj\n", nObjectId, nGen);
497 1210 : bInWriteObj = TRUE;
498 1210 : }
499 :
500 : /************************************************************************/
501 : /* EndObj() */
502 : /************************************************************************/
503 :
504 1210 : void GDALPDFWriter::EndObj()
505 : {
506 1210 : CPLAssert(bInWriteObj);
507 1210 : VSIFPrintfL(fp, "endobj\n");
508 1210 : bInWriteObj = FALSE;
509 1210 : }
510 :
511 :
512 : /************************************************************************/
513 : /* GDALPDFFind4Corners() */
514 : /************************************************************************/
515 :
516 : static
517 24 : void GDALPDFFind4Corners(const GDAL_GCP* pasGCPList,
518 : int& iUL, int& iUR, int& iLR, int& iLL)
519 : {
520 24 : double dfMeanX = 0, dfMeanY = 0;
521 : int i;
522 :
523 24 : iUL = 0;
524 24 : iUR = 0;
525 24 : iLR = 0;
526 24 : iLL = 0;
527 :
528 120 : for(i = 0; i < 4; i++ )
529 : {
530 96 : dfMeanX += pasGCPList[i].dfGCPPixel;
531 96 : dfMeanY += pasGCPList[i].dfGCPLine;
532 : }
533 24 : dfMeanX /= 4;
534 24 : dfMeanY /= 4;
535 :
536 120 : for(i = 0; i < 4; i++ )
537 : {
538 168 : if (pasGCPList[i].dfGCPPixel < dfMeanX &&
539 48 : pasGCPList[i].dfGCPLine < dfMeanY )
540 24 : iUL = i;
541 :
542 144 : else if (pasGCPList[i].dfGCPPixel > dfMeanX &&
543 48 : pasGCPList[i].dfGCPLine < dfMeanY )
544 24 : iUR = i;
545 :
546 96 : else if (pasGCPList[i].dfGCPPixel > dfMeanX &&
547 24 : pasGCPList[i].dfGCPLine > dfMeanY )
548 24 : iLR = i;
549 :
550 48 : else if (pasGCPList[i].dfGCPPixel < dfMeanX &&
551 24 : pasGCPList[i].dfGCPLine > dfMeanY )
552 24 : iLL = i;
553 : }
554 24 : }
555 :
556 : /************************************************************************/
557 : /* WriteSRS_ISO32000() */
558 : /************************************************************************/
559 :
560 94 : int GDALPDFWriter::WriteSRS_ISO32000(GDALDataset* poSrcDS,
561 : double dfUserUnit,
562 : const char* pszNEATLINE,
563 : PDFMargins* psMargins)
564 : {
565 94 : int nWidth = poSrcDS->GetRasterXSize();
566 94 : int nHeight = poSrcDS->GetRasterYSize();
567 94 : const char* pszWKT = poSrcDS->GetProjectionRef();
568 : double adfGeoTransform[6];
569 :
570 94 : int bHasGT = (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None);
571 94 : const GDAL_GCP* pasGCPList = (poSrcDS->GetGCPCount() == 4) ? poSrcDS->GetGCPs() : NULL;
572 94 : if (pasGCPList != NULL)
573 2 : pszWKT = poSrcDS->GetGCPProjection();
574 :
575 94 : if( !bHasGT && pasGCPList == NULL )
576 8 : return 0;
577 :
578 86 : if( pszWKT == NULL || EQUAL(pszWKT, "") )
579 4 : return 0;
580 :
581 : double adfGPTS[8];
582 :
583 82 : double dfULPixel = 0;
584 82 : double dfULLine = 0;
585 82 : double dfLRPixel = nWidth;
586 82 : double dfLRLine = nHeight;
587 :
588 : GDAL_GCP asNeatLineGCPs[4];
589 82 : if (pszNEATLINE == NULL)
590 80 : pszNEATLINE = poSrcDS->GetMetadataItem("NEATLINE");
591 82 : if( bHasGT && pszNEATLINE != NULL && pszNEATLINE[0] != '\0' )
592 : {
593 10 : OGRGeometry* poGeom = NULL;
594 10 : OGRGeometryFactory::createFromWkt( (char**)&pszNEATLINE, NULL, &poGeom );
595 10 : if ( poGeom != NULL && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
596 : {
597 10 : OGRLineString* poLS = ((OGRPolygon*)poGeom)->getExteriorRing();
598 : double adfGeoTransformInv[6];
599 10 : if( poLS != NULL && poLS->getNumPoints() == 5 &&
600 : GDALInvGeoTransform(adfGeoTransform, adfGeoTransformInv) )
601 : {
602 50 : for(int i=0;i<4;i++)
603 : {
604 40 : double X = asNeatLineGCPs[i].dfGCPX = poLS->getX(i);
605 40 : double Y = asNeatLineGCPs[i].dfGCPY = poLS->getY(i);
606 40 : double x = adfGeoTransformInv[0] + X * adfGeoTransformInv[1] + Y * adfGeoTransformInv[2];
607 40 : double y = adfGeoTransformInv[3] + X * adfGeoTransformInv[4] + Y * adfGeoTransformInv[5];
608 40 : asNeatLineGCPs[i].dfGCPPixel = x;
609 40 : asNeatLineGCPs[i].dfGCPLine = y;
610 : }
611 :
612 10 : int iUL = 0, iUR = 0, iLR = 0, iLL = 0;
613 : GDALPDFFind4Corners(asNeatLineGCPs,
614 10 : iUL,iUR, iLR, iLL);
615 :
616 10 : if (fabs(asNeatLineGCPs[iUL].dfGCPPixel - asNeatLineGCPs[iLL].dfGCPPixel) > .5 ||
617 : fabs(asNeatLineGCPs[iUR].dfGCPPixel - asNeatLineGCPs[iLR].dfGCPPixel) > .5 ||
618 : fabs(asNeatLineGCPs[iUL].dfGCPLine - asNeatLineGCPs[iUR].dfGCPLine) > .5 ||
619 : fabs(asNeatLineGCPs[iLL].dfGCPLine - asNeatLineGCPs[iLR].dfGCPLine) > .5)
620 : {
621 : CPLError(CE_Warning, CPLE_NotSupported,
622 0 : "Neatline coordinates should form a rectangle in pixel space. Ignoring it");
623 0 : for(int i=0;i<4;i++)
624 : {
625 : CPLDebug("PDF", "pixel[%d] = %.1f, line[%d] = %.1f",
626 : i, asNeatLineGCPs[i].dfGCPPixel,
627 0 : i, asNeatLineGCPs[i].dfGCPLine);
628 : }
629 : }
630 : else
631 : {
632 10 : pasGCPList = asNeatLineGCPs;
633 : }
634 : }
635 : }
636 10 : delete poGeom;
637 : }
638 :
639 82 : if( pasGCPList )
640 : {
641 12 : int iUL = 0, iUR = 0, iLR = 0, iLL = 0;
642 : GDALPDFFind4Corners(pasGCPList,
643 12 : iUL,iUR, iLR, iLL);
644 :
645 84 : if (fabs(pasGCPList[iUL].dfGCPPixel - pasGCPList[iLL].dfGCPPixel) > .5 ||
646 24 : fabs(pasGCPList[iUR].dfGCPPixel - pasGCPList[iLR].dfGCPPixel) > .5 ||
647 24 : fabs(pasGCPList[iUL].dfGCPLine - pasGCPList[iUR].dfGCPLine) > .5 ||
648 24 : fabs(pasGCPList[iLL].dfGCPLine - pasGCPList[iLR].dfGCPLine) > .5)
649 : {
650 : CPLError(CE_Failure, CPLE_NotSupported,
651 0 : "GCPs should form a rectangle in pixel space");
652 0 : return 0;
653 : }
654 :
655 12 : dfULPixel = pasGCPList[iUL].dfGCPPixel;
656 12 : dfULLine = pasGCPList[iUL].dfGCPLine;
657 12 : dfLRPixel = pasGCPList[iLR].dfGCPPixel;
658 12 : dfLRLine = pasGCPList[iLR].dfGCPLine;
659 :
660 : /* Upper-left */
661 12 : adfGPTS[0] = pasGCPList[iUL].dfGCPX;
662 12 : adfGPTS[1] = pasGCPList[iUL].dfGCPY;
663 :
664 : /* Lower-left */
665 12 : adfGPTS[2] = pasGCPList[iLL].dfGCPX;
666 12 : adfGPTS[3] = pasGCPList[iLL].dfGCPY;
667 :
668 : /* Lower-right */
669 12 : adfGPTS[4] = pasGCPList[iLR].dfGCPX;
670 12 : adfGPTS[5] = pasGCPList[iLR].dfGCPY;
671 :
672 : /* Upper-right */
673 12 : adfGPTS[6] = pasGCPList[iUR].dfGCPX;
674 12 : adfGPTS[7] = pasGCPList[iUR].dfGCPY;
675 : }
676 : else
677 : {
678 : /* Upper-left */
679 70 : adfGPTS[0] = PIXEL_TO_GEO_X(0, 0);
680 70 : adfGPTS[1] = PIXEL_TO_GEO_Y(0, 0);
681 :
682 : /* Lower-left */
683 70 : adfGPTS[2] = PIXEL_TO_GEO_X(0, nHeight);
684 70 : adfGPTS[3] = PIXEL_TO_GEO_Y(0, nHeight);
685 :
686 : /* Lower-right */
687 70 : adfGPTS[4] = PIXEL_TO_GEO_X(nWidth, nHeight);
688 70 : adfGPTS[5] = PIXEL_TO_GEO_Y(nWidth, nHeight);
689 :
690 : /* Upper-right */
691 70 : adfGPTS[6] = PIXEL_TO_GEO_X(nWidth, 0);
692 70 : adfGPTS[7] = PIXEL_TO_GEO_Y(nWidth, 0);
693 : }
694 :
695 82 : OGRSpatialReferenceH hSRS = OSRNewSpatialReference(pszWKT);
696 82 : if( hSRS == NULL )
697 0 : return 0;
698 82 : OGRSpatialReferenceH hSRSGeog = OSRCloneGeogCS(hSRS);
699 82 : if( hSRSGeog == NULL )
700 : {
701 0 : OSRDestroySpatialReference(hSRS);
702 0 : return 0;
703 : }
704 82 : OGRCoordinateTransformationH hCT = OCTNewCoordinateTransformation( hSRS, hSRSGeog);
705 82 : if( hCT == NULL )
706 : {
707 0 : OSRDestroySpatialReference(hSRS);
708 0 : OSRDestroySpatialReference(hSRSGeog);
709 0 : return 0;
710 : }
711 :
712 82 : int bSuccess = TRUE;
713 :
714 82 : bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 0, adfGPTS + 1, NULL ) == 1);
715 82 : bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 2, adfGPTS + 3, NULL ) == 1);
716 82 : bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 4, adfGPTS + 5, NULL ) == 1);
717 82 : bSuccess &= (OCTTransform( hCT, 1, adfGPTS + 6, adfGPTS + 7, NULL ) == 1);
718 :
719 82 : if (!bSuccess)
720 : {
721 0 : OSRDestroySpatialReference(hSRS);
722 0 : OSRDestroySpatialReference(hSRSGeog);
723 0 : OCTDestroyCoordinateTransformation(hCT);
724 0 : return 0;
725 : }
726 :
727 82 : const char * pszAuthorityCode = OSRGetAuthorityCode( hSRS, NULL );
728 82 : const char * pszAuthorityName = OSRGetAuthorityName( hSRS, NULL );
729 82 : int nEPSGCode = 0;
730 82 : if( pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG") &&
731 : pszAuthorityCode != NULL )
732 78 : nEPSGCode = atoi(pszAuthorityCode);
733 :
734 82 : int bIsGeographic = OSRIsGeographic(hSRS);
735 :
736 82 : OSRMorphToESRI(hSRS);
737 82 : char* pszESRIWKT = NULL;
738 82 : OSRExportToWkt(hSRS, &pszESRIWKT);
739 :
740 82 : OSRDestroySpatialReference(hSRS);
741 82 : OSRDestroySpatialReference(hSRSGeog);
742 82 : OCTDestroyCoordinateTransformation(hCT);
743 82 : hSRS = NULL;
744 82 : hSRSGeog = NULL;
745 82 : hCT = NULL;
746 :
747 82 : if (pszESRIWKT == NULL)
748 0 : return 0;
749 :
750 82 : int nViewportId = AllocNewObject();
751 82 : int nMeasureId = AllocNewObject();
752 82 : int nGCSId = AllocNewObject();
753 :
754 82 : StartObj(nViewportId);
755 82 : GDALPDFDictionaryRW oViewPortDict;
756 : oViewPortDict.Add("Type", GDALPDFObjectRW::CreateName("Viewport"))
757 : .Add("Name", "Layer")
758 : .Add("BBox", &((new GDALPDFArrayRW())
759 : ->Add(dfULPixel / dfUserUnit + psMargins->nLeft)
760 : .Add((nHeight - dfLRLine) / dfUserUnit + psMargins->nBottom)
761 : .Add(dfLRPixel / dfUserUnit + psMargins->nLeft)
762 : .Add((nHeight - dfULLine) / dfUserUnit + psMargins->nBottom)))
763 82 : .Add("Measure", nMeasureId, 0);
764 82 : VSIFPrintfL(fp, "%s\n", oViewPortDict.Serialize().c_str());
765 82 : EndObj();
766 :
767 82 : StartObj(nMeasureId);
768 82 : GDALPDFDictionaryRW oMeasureDict;
769 : oMeasureDict .Add("Type", GDALPDFObjectRW::CreateName("Measure"))
770 : .Add("Subtype", GDALPDFObjectRW::CreateName("GEO"))
771 : .Add("Bounds", &((new GDALPDFArrayRW())
772 : ->Add(0).Add(1).
773 : Add(0).Add(0).
774 : Add(1).Add(0).
775 : Add(1).Add(1)))
776 : .Add("GPTS", &((new GDALPDFArrayRW())
777 : ->Add(adfGPTS[1]).Add(adfGPTS[0]).
778 : Add(adfGPTS[3]).Add(adfGPTS[2]).
779 : Add(adfGPTS[5]).Add(adfGPTS[4]).
780 : Add(adfGPTS[7]).Add(adfGPTS[6])))
781 : .Add("LPTS", &((new GDALPDFArrayRW())
782 : ->Add(0).Add(1).
783 : Add(0).Add(0).
784 : Add(1).Add(0).
785 : Add(1).Add(1)))
786 82 : .Add("GCS", nGCSId, 0);
787 82 : VSIFPrintfL(fp, "%s\n", oMeasureDict.Serialize().c_str());
788 82 : EndObj();
789 :
790 :
791 82 : StartObj(nGCSId);
792 82 : GDALPDFDictionaryRW oGCSDict;
793 : oGCSDict.Add("Type", GDALPDFObjectRW::CreateName(bIsGeographic ? "GEOGCS" : "PROJCS"))
794 82 : .Add("WKT", pszESRIWKT);
795 82 : if (nEPSGCode)
796 78 : oGCSDict.Add("EPSG", nEPSGCode);
797 82 : VSIFPrintfL(fp, "%s\n", oGCSDict.Serialize().c_str());
798 82 : EndObj();
799 :
800 82 : CPLFree(pszESRIWKT);
801 :
802 82 : return nViewportId;
803 : }
804 :
805 : /************************************************************************/
806 : /* GDALPDFBuildOGC_BP_Datum() */
807 : /************************************************************************/
808 :
809 14 : static GDALPDFObject* GDALPDFBuildOGC_BP_Datum(const OGRSpatialReference* poSRS)
810 : {
811 14 : const OGR_SRSNode* poDatumNode = poSRS->GetAttrNode("DATUM");
812 14 : const char* pszDatumDescription = NULL;
813 14 : if (poDatumNode && poDatumNode->GetChildCount() > 0)
814 14 : pszDatumDescription = poDatumNode->GetChild(0)->GetValue();
815 :
816 14 : GDALPDFObjectRW* poPDFDatum = NULL;
817 :
818 14 : if (pszDatumDescription)
819 : {
820 14 : double dfSemiMajor = poSRS->GetSemiMajor();
821 14 : double dfInvFlattening = poSRS->GetInvFlattening();
822 14 : int nEPSGDatum = -1;
823 14 : const char *pszAuthority = poSRS->GetAuthorityName( "DATUM" );
824 14 : if( pszAuthority != NULL && EQUAL(pszAuthority,"EPSG") )
825 14 : nEPSGDatum = atoi(poSRS->GetAuthorityCode( "DATUM" ));
826 :
827 16 : if( EQUAL(pszDatumDescription,SRS_DN_WGS84) || nEPSGDatum == 6326 )
828 2 : poPDFDatum = GDALPDFObjectRW::CreateString("WGE");
829 24 : else if( EQUAL(pszDatumDescription, SRS_DN_NAD27) || nEPSGDatum == 6267 )
830 12 : poPDFDatum = GDALPDFObjectRW::CreateString("NAS");
831 0 : else if( EQUAL(pszDatumDescription, SRS_DN_NAD83) || nEPSGDatum == 6269 )
832 0 : poPDFDatum = GDALPDFObjectRW::CreateString("NAR");
833 : else
834 : {
835 : CPLDebug("PDF",
836 : "Unhandled datum name (%s). Write datum parameters then.",
837 0 : pszDatumDescription);
838 :
839 0 : GDALPDFDictionaryRW* poPDFDatumDict = new GDALPDFDictionaryRW();
840 0 : poPDFDatum = GDALPDFObjectRW::CreateDictionary(poPDFDatumDict);
841 :
842 0 : const OGR_SRSNode* poSpheroidNode = poSRS->GetAttrNode("SPHEROID");
843 0 : if (poSpheroidNode && poSpheroidNode->GetChildCount() >= 3)
844 : {
845 0 : poPDFDatumDict->Add("Description", pszDatumDescription);
846 :
847 0 : const char* pszEllipsoidCode = NULL;
848 : #ifdef disabled_because_terrago_toolbar_does_not_like_it
849 : if( ABS(dfSemiMajor-6378249.145) < 0.01
850 : && ABS(dfInvFlattening-293.465) < 0.0001 )
851 : {
852 : pszEllipsoidCode = "CD"; /* Clark 1880 */
853 : }
854 : else if( ABS(dfSemiMajor-6378245.0) < 0.01
855 : && ABS(dfInvFlattening-298.3) < 0.0001 )
856 : {
857 : pszEllipsoidCode = "KA"; /* Krassovsky */
858 : }
859 : else if( ABS(dfSemiMajor-6378388.0) < 0.01
860 : && ABS(dfInvFlattening-297.0) < 0.0001 )
861 : {
862 : pszEllipsoidCode = "IN"; /* International 1924 */
863 : }
864 : else if( ABS(dfSemiMajor-6378160.0) < 0.01
865 : && ABS(dfInvFlattening-298.25) < 0.0001 )
866 : {
867 : pszEllipsoidCode = "AN"; /* Australian */
868 : }
869 : else if( ABS(dfSemiMajor-6377397.155) < 0.01
870 : && ABS(dfInvFlattening-299.1528128) < 0.0001 )
871 : {
872 : pszEllipsoidCode = "BR"; /* Bessel 1841 */
873 : }
874 : else if( ABS(dfSemiMajor-6377483.865) < 0.01
875 : && ABS(dfInvFlattening-299.1528128) < 0.0001 )
876 : {
877 : pszEllipsoidCode = "BN"; /* Bessel 1841 (Namibia / Schwarzeck)*/
878 : }
879 : #if 0
880 : else if( ABS(dfSemiMajor-6378160.0) < 0.01
881 : && ABS(dfInvFlattening-298.247167427) < 0.0001 )
882 : {
883 : pszEllipsoidCode = "GRS67"; /* GRS 1967 */
884 : }
885 : #endif
886 : else if( ABS(dfSemiMajor-6378137) < 0.01
887 : && ABS(dfInvFlattening-298.257222101) < 0.000001 )
888 : {
889 : pszEllipsoidCode = "RF"; /* GRS 1980 */
890 : }
891 : else if( ABS(dfSemiMajor-6378206.4) < 0.01
892 : && ABS(dfInvFlattening-294.9786982) < 0.0001 )
893 : {
894 : pszEllipsoidCode = "CC"; /* Clarke 1866 */
895 : }
896 : else if( ABS(dfSemiMajor-6377340.189) < 0.01
897 : && ABS(dfInvFlattening-299.3249646) < 0.0001 )
898 : {
899 : pszEllipsoidCode = "AM"; /* Modified Airy */
900 : }
901 : else if( ABS(dfSemiMajor-6377563.396) < 0.01
902 : && ABS(dfInvFlattening-299.3249646) < 0.0001 )
903 : {
904 : pszEllipsoidCode = "AA"; /* Airy */
905 : }
906 : else if( ABS(dfSemiMajor-6378200) < 0.01
907 : && ABS(dfInvFlattening-298.3) < 0.0001 )
908 : {
909 : pszEllipsoidCode = "HE"; /* Helmert 1906 */
910 : }
911 : else if( ABS(dfSemiMajor-6378155) < 0.01
912 : && ABS(dfInvFlattening-298.3) < 0.0001 )
913 : {
914 : pszEllipsoidCode = "FA"; /* Modified Fischer 1960 */
915 : }
916 : #if 0
917 : else if( ABS(dfSemiMajor-6377298.556) < 0.01
918 : && ABS(dfInvFlattening-300.8017) < 0.0001 )
919 : {
920 : pszEllipsoidCode = "evrstSS"; /* Everest (Sabah & Sarawak) */
921 : }
922 : else if( ABS(dfSemiMajor-6378165.0) < 0.01
923 : && ABS(dfInvFlattening-298.3) < 0.0001 )
924 : {
925 : pszEllipsoidCode = "WGS60";
926 : }
927 : else if( ABS(dfSemiMajor-6378145.0) < 0.01
928 : && ABS(dfInvFlattening-298.25) < 0.0001 )
929 : {
930 : pszEllipsoidCode = "WGS66";
931 : }
932 : #endif
933 : else if( ABS(dfSemiMajor-6378135.0) < 0.01
934 : && ABS(dfInvFlattening-298.26) < 0.0001 )
935 : {
936 : pszEllipsoidCode = "WD";
937 : }
938 : else if( ABS(dfSemiMajor-6378137.0) < 0.01
939 : && ABS(dfInvFlattening-298.257223563) < 0.000001 )
940 : {
941 : pszEllipsoidCode = "WE";
942 : }
943 : #endif
944 :
945 0 : if( pszEllipsoidCode != NULL )
946 : {
947 0 : poPDFDatumDict->Add("Ellipsoid", pszEllipsoidCode);
948 : }
949 : else
950 : {
951 : const char* pszEllipsoidDescription =
952 0 : poSpheroidNode->GetChild(0)->GetValue();
953 :
954 : CPLDebug("PDF",
955 : "Unhandled ellipsoid name (%s). Write ellipsoid parameters then.",
956 0 : pszEllipsoidDescription);
957 :
958 : poPDFDatumDict->Add("Ellipsoid",
959 : &((new GDALPDFDictionaryRW())
960 : ->Add("Description", pszEllipsoidDescription)
961 : .Add("SemiMajorAxis", dfSemiMajor, TRUE)
962 0 : .Add("InvFlattening", dfInvFlattening, TRUE)));
963 : }
964 :
965 0 : const OGR_SRSNode *poTOWGS84 = poSRS->GetAttrNode( "TOWGS84" );
966 0 : if( poTOWGS84 != NULL
967 : && poTOWGS84->GetChildCount() >= 3
968 : && (poTOWGS84->GetChildCount() < 7
969 : || (EQUAL(poTOWGS84->GetChild(3)->GetValue(),"")
970 : && EQUAL(poTOWGS84->GetChild(4)->GetValue(),"")
971 : && EQUAL(poTOWGS84->GetChild(5)->GetValue(),"")
972 : && EQUAL(poTOWGS84->GetChild(6)->GetValue(),""))) )
973 : {
974 : poPDFDatumDict->Add("ToWGS84",
975 : &((new GDALPDFDictionaryRW())
976 : ->Add("dx", poTOWGS84->GetChild(0)->GetValue())
977 : .Add("dy", poTOWGS84->GetChild(1)->GetValue())
978 0 : .Add("dz", poTOWGS84->GetChild(2)->GetValue())) );
979 : }
980 0 : else if( poTOWGS84 != NULL && poTOWGS84->GetChildCount() >= 7)
981 : {
982 : poPDFDatumDict->Add("ToWGS84",
983 : &((new GDALPDFDictionaryRW())
984 : ->Add("dx", poTOWGS84->GetChild(0)->GetValue())
985 : .Add("dy", poTOWGS84->GetChild(1)->GetValue())
986 : .Add("dz", poTOWGS84->GetChild(2)->GetValue())
987 : .Add("rx", poTOWGS84->GetChild(3)->GetValue())
988 : .Add("ry", poTOWGS84->GetChild(4)->GetValue())
989 : .Add("rz", poTOWGS84->GetChild(5)->GetValue())
990 0 : .Add("sf", poTOWGS84->GetChild(6)->GetValue())) );
991 : }
992 : }
993 : }
994 : }
995 : else
996 : {
997 : CPLError(CE_Warning, CPLE_NotSupported,
998 0 : "No datum name. Defaulting to WGS84.");
999 : }
1000 :
1001 14 : if (poPDFDatum == NULL)
1002 0 : poPDFDatum = GDALPDFObjectRW::CreateString("WGE");
1003 :
1004 14 : return poPDFDatum;
1005 : }
1006 :
1007 : /************************************************************************/
1008 : /* GDALPDFBuildOGC_BP_Projection() */
1009 : /************************************************************************/
1010 :
1011 14 : static GDALPDFDictionaryRW* GDALPDFBuildOGC_BP_Projection(const OGRSpatialReference* poSRS)
1012 : {
1013 :
1014 14 : const char* pszProjectionOGCBP = "GEOGRAPHIC";
1015 14 : const char *pszProjection = poSRS->GetAttrValue("PROJECTION");
1016 :
1017 14 : GDALPDFDictionaryRW* poProjectionDict = new GDALPDFDictionaryRW();
1018 14 : poProjectionDict->Add("Type", GDALPDFObjectRW::CreateName("Projection"));
1019 14 : poProjectionDict->Add("Datum", GDALPDFBuildOGC_BP_Datum(poSRS));
1020 :
1021 14 : if( pszProjection == NULL )
1022 : {
1023 2 : if( poSRS->IsGeographic() )
1024 2 : pszProjectionOGCBP = "GEOGRAPHIC";
1025 0 : else if( poSRS->IsLocal() )
1026 0 : pszProjectionOGCBP = "LOCAL CARTESIAN";
1027 : else
1028 : {
1029 0 : CPLError(CE_Warning, CPLE_NotSupported, "Unsupported SRS type");
1030 0 : delete poProjectionDict;
1031 0 : return NULL;
1032 : }
1033 : }
1034 12 : else if( EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR) )
1035 : {
1036 : int bNorth;
1037 12 : int nZone = poSRS->GetUTMZone( &bNorth );
1038 :
1039 12 : if( nZone != 0 )
1040 : {
1041 12 : pszProjectionOGCBP = "UT";
1042 12 : poProjectionDict->Add("Hemisphere", (bNorth) ? "N" : "S");
1043 12 : poProjectionDict->Add("Zone", nZone);
1044 : }
1045 : else
1046 : {
1047 0 : double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,90.L);
1048 0 : double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
1049 0 : double dfScale = poSRS->GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0);
1050 0 : double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
1051 0 : double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
1052 :
1053 : /* OGC_BP supports representing numbers as strings for better precision */
1054 : /* so use it */
1055 :
1056 0 : pszProjectionOGCBP = "TC";
1057 0 : poProjectionDict->Add("OriginLatitude", dfCenterLat, TRUE);
1058 0 : poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
1059 0 : poProjectionDict->Add("ScaleFactor", dfScale, TRUE);
1060 0 : poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
1061 0 : poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
1062 : }
1063 : }
1064 0 : else if( EQUAL(pszProjection,SRS_PT_POLAR_STEREOGRAPHIC) )
1065 : {
1066 0 : double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
1067 0 : double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
1068 0 : double dfScale = poSRS->GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0);
1069 0 : double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
1070 0 : double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
1071 :
1072 0 : if( fabs(dfCenterLat) == 90.0 && dfCenterLong == 0.0 &&
1073 : dfScale == 0.994 && dfFalseEasting == 200000.0 && dfFalseNorthing == 200000.0)
1074 : {
1075 0 : pszProjectionOGCBP = "UP";
1076 0 : poProjectionDict->Add("Hemisphere", (dfCenterLat > 0) ? "N" : "S");
1077 : }
1078 : else
1079 : {
1080 0 : pszProjectionOGCBP = "PG";
1081 0 : poProjectionDict->Add("LatitudeTrueScale", dfCenterLat, TRUE);
1082 0 : poProjectionDict->Add("LongitudeDownFromPole", dfCenterLong, TRUE);
1083 0 : poProjectionDict->Add("ScaleFactor", dfScale, TRUE);
1084 0 : poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
1085 0 : poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
1086 : }
1087 : }
1088 :
1089 0 : else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP))
1090 : {
1091 0 : double dfStdP1 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
1092 0 : double dfStdP2 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
1093 0 : double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
1094 0 : double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
1095 0 : double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
1096 0 : double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
1097 :
1098 0 : pszProjectionOGCBP = "LE";
1099 0 : poProjectionDict->Add("StandardParallelOne", dfStdP1, TRUE);
1100 0 : poProjectionDict->Add("StandardParallelTwo", dfStdP2, TRUE);
1101 0 : poProjectionDict->Add("OriginLatitude", dfCenterLat, TRUE);
1102 0 : poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
1103 0 : poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
1104 0 : poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
1105 : }
1106 :
1107 0 : else if( EQUAL(pszProjection,SRS_PT_MERCATOR_1SP) )
1108 : {
1109 0 : double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
1110 0 : double dfCenterLat = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
1111 0 : double dfScale = poSRS->GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0);
1112 0 : double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
1113 0 : double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
1114 :
1115 0 : pszProjectionOGCBP = "MC";
1116 0 : poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
1117 0 : poProjectionDict->Add("OriginLatitude", dfCenterLat, TRUE);
1118 0 : poProjectionDict->Add("ScaleFactor", dfScale, TRUE);
1119 0 : poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
1120 0 : poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
1121 : }
1122 :
1123 : #ifdef not_supported
1124 : else if( EQUAL(pszProjection,SRS_PT_MERCATOR_2SP) )
1125 : {
1126 : double dfStdP1 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
1127 : double dfCenterLong = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
1128 : double dfFalseEasting = poSRS->GetNormProjParm(SRS_PP_FALSE_EASTING,0.0);
1129 : double dfFalseNorthing = poSRS->GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0);
1130 :
1131 : pszProjectionOGCBP = "MC";
1132 : poProjectionDict->Add("StandardParallelOne", dfStdP1, TRUE);
1133 : poProjectionDict->Add("CentralMeridian", dfCenterLong, TRUE);
1134 : poProjectionDict->Add("FalseEasting", dfFalseEasting, TRUE);
1135 : poProjectionDict->Add("FalseNorthing", dfFalseNorthing, TRUE);
1136 : }
1137 : #endif
1138 :
1139 : else
1140 : {
1141 : CPLError(CE_Warning, CPLE_NotSupported,
1142 0 : "Unhandled projection type (%s) for now", pszProjection);
1143 : }
1144 :
1145 14 : poProjectionDict->Add("ProjectionType", pszProjectionOGCBP);
1146 :
1147 14 : if( poSRS->IsProjected() )
1148 : {
1149 12 : char* pszUnitName = NULL;
1150 12 : double dfLinearUnits = poSRS->GetLinearUnits(&pszUnitName);
1151 12 : if (dfLinearUnits == 1.0)
1152 12 : poProjectionDict->Add("Units", "M");
1153 0 : else if (dfLinearUnits == 0.3048)
1154 0 : poProjectionDict->Add("Units", "FT");
1155 : }
1156 :
1157 14 : return poProjectionDict;
1158 : }
1159 :
1160 : /************************************************************************/
1161 : /* WriteSRS_OGC_BP() */
1162 : /************************************************************************/
1163 :
1164 14 : int GDALPDFWriter::WriteSRS_OGC_BP(GDALDataset* poSrcDS,
1165 : double dfUserUnit,
1166 : const char* pszNEATLINE,
1167 : PDFMargins* psMargins)
1168 : {
1169 14 : int nWidth = poSrcDS->GetRasterXSize();
1170 14 : int nHeight = poSrcDS->GetRasterYSize();
1171 14 : const char* pszWKT = poSrcDS->GetProjectionRef();
1172 : double adfGeoTransform[6];
1173 :
1174 14 : int bHasGT = (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None);
1175 14 : int nGCPCount = poSrcDS->GetGCPCount();
1176 14 : const GDAL_GCP* pasGCPList = (nGCPCount >= 4) ? poSrcDS->GetGCPs() : NULL;
1177 14 : if (pasGCPList != NULL)
1178 4 : pszWKT = poSrcDS->GetGCPProjection();
1179 :
1180 14 : if( !bHasGT && pasGCPList == NULL )
1181 0 : return 0;
1182 :
1183 14 : if( pszWKT == NULL || EQUAL(pszWKT, "") )
1184 0 : return 0;
1185 :
1186 14 : if( !bHasGT )
1187 : {
1188 4 : if (!GDALGCPsToGeoTransform( nGCPCount, pasGCPList,
1189 : adfGeoTransform, FALSE ))
1190 : {
1191 2 : CPLDebug("PDF", "Could not compute GT with exact match. Writing Registration then");
1192 : }
1193 : else
1194 : {
1195 2 : bHasGT = TRUE;
1196 : }
1197 : }
1198 :
1199 14 : OGRSpatialReferenceH hSRS = OSRNewSpatialReference(pszWKT);
1200 14 : if( hSRS == NULL )
1201 0 : return 0;
1202 :
1203 14 : const OGRSpatialReference* poSRS = (const OGRSpatialReference*)hSRS;
1204 14 : GDALPDFDictionaryRW* poProjectionDict = GDALPDFBuildOGC_BP_Projection(poSRS);
1205 14 : if (poProjectionDict == NULL)
1206 : {
1207 0 : OSRDestroySpatialReference(hSRS);
1208 0 : return 0;
1209 : }
1210 :
1211 14 : GDALPDFArrayRW* poNeatLineArray = NULL;
1212 :
1213 14 : if (pszNEATLINE == NULL)
1214 12 : pszNEATLINE = poSrcDS->GetMetadataItem("NEATLINE");
1215 14 : if( bHasGT && pszNEATLINE != NULL && !EQUAL(pszNEATLINE, "NO") && pszNEATLINE[0] != '\0' )
1216 : {
1217 2 : OGRGeometry* poGeom = NULL;
1218 2 : OGRGeometryFactory::createFromWkt( (char**)&pszNEATLINE, NULL, &poGeom );
1219 2 : if ( poGeom != NULL && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon )
1220 : {
1221 2 : OGRLineString* poLS = ((OGRPolygon*)poGeom)->getExteriorRing();
1222 : double adfGeoTransformInv[6];
1223 2 : if( poLS != NULL && poLS->getNumPoints() >= 5 &&
1224 : GDALInvGeoTransform(adfGeoTransform, adfGeoTransformInv) )
1225 : {
1226 2 : poNeatLineArray = new GDALPDFArrayRW();
1227 :
1228 : // FIXME : ensure that they are in clockwise order ?
1229 12 : for(int i=0;i<poLS->getNumPoints() - 1;i++)
1230 : {
1231 10 : double X = poLS->getX(i);
1232 10 : double Y = poLS->getY(i);
1233 10 : double x = adfGeoTransformInv[0] + X * adfGeoTransformInv[1] + Y * adfGeoTransformInv[2];
1234 10 : double y = adfGeoTransformInv[3] + X * adfGeoTransformInv[4] + Y * adfGeoTransformInv[5];
1235 10 : poNeatLineArray->Add(x / dfUserUnit + psMargins->nLeft, TRUE);
1236 10 : poNeatLineArray->Add((nHeight - y) / dfUserUnit + psMargins->nBottom, TRUE);
1237 : }
1238 : }
1239 : }
1240 2 : delete poGeom;
1241 : }
1242 :
1243 14 : if( pszNEATLINE != NULL && EQUAL(pszNEATLINE, "NO") )
1244 : {
1245 : // Do nothing
1246 : }
1247 18 : else if( pasGCPList && poNeatLineArray == NULL)
1248 : {
1249 4 : if (nGCPCount == 4)
1250 : {
1251 2 : int iUL = 0, iUR = 0, iLR = 0, iLL = 0;
1252 : GDALPDFFind4Corners(pasGCPList,
1253 2 : iUL,iUR, iLR, iLL);
1254 :
1255 : double adfNL[8];
1256 2 : adfNL[0] = pasGCPList[iUL].dfGCPPixel / dfUserUnit + psMargins->nLeft;
1257 2 : adfNL[1] = (nHeight - pasGCPList[iUL].dfGCPLine) / dfUserUnit + psMargins->nBottom;
1258 2 : adfNL[2] = pasGCPList[iLL].dfGCPPixel / dfUserUnit + psMargins->nLeft;
1259 2 : adfNL[3] = (nHeight - pasGCPList[iLL].dfGCPLine) / dfUserUnit + psMargins->nBottom;
1260 2 : adfNL[4] = pasGCPList[iLR].dfGCPPixel / dfUserUnit + psMargins->nLeft;
1261 2 : adfNL[5] = (nHeight - pasGCPList[iLR].dfGCPLine) / dfUserUnit + psMargins->nBottom;
1262 2 : adfNL[6] = pasGCPList[iUR].dfGCPPixel / dfUserUnit + psMargins->nLeft;
1263 2 : adfNL[7] = (nHeight - pasGCPList[iUR].dfGCPLine) / dfUserUnit + psMargins->nBottom;
1264 :
1265 2 : poNeatLineArray = new GDALPDFArrayRW();
1266 2 : poNeatLineArray->Add(adfNL, 8, TRUE);
1267 : }
1268 : else
1269 : {
1270 2 : poNeatLineArray = new GDALPDFArrayRW();
1271 :
1272 : // FIXME : ensure that they are in clockwise order ?
1273 : int i;
1274 12 : for(i = 0; i < nGCPCount; i++)
1275 : {
1276 10 : poNeatLineArray->Add(pasGCPList[i].dfGCPPixel / dfUserUnit + psMargins->nLeft, TRUE);
1277 10 : poNeatLineArray->Add((nHeight - pasGCPList[i].dfGCPLine) / dfUserUnit + psMargins->nBottom, TRUE);
1278 : }
1279 : }
1280 : }
1281 10 : else if (poNeatLineArray == NULL)
1282 : {
1283 8 : poNeatLineArray = new GDALPDFArrayRW();
1284 :
1285 8 : poNeatLineArray->Add(0 / dfUserUnit + psMargins->nLeft, TRUE);
1286 8 : poNeatLineArray->Add((nHeight - 0) / dfUserUnit + psMargins->nBottom, TRUE);
1287 :
1288 8 : poNeatLineArray->Add(0 / dfUserUnit + psMargins->nLeft, TRUE);
1289 8 : poNeatLineArray->Add((nHeight -nHeight) / dfUserUnit + psMargins->nBottom, TRUE);
1290 :
1291 8 : poNeatLineArray->Add(nWidth / dfUserUnit + psMargins->nLeft, TRUE);
1292 8 : poNeatLineArray->Add((nHeight -nHeight) / dfUserUnit + psMargins->nBottom, TRUE);
1293 :
1294 8 : poNeatLineArray->Add(nWidth / dfUserUnit + psMargins->nLeft, TRUE);
1295 8 : poNeatLineArray->Add((nHeight - 0) / dfUserUnit + psMargins->nBottom, TRUE);
1296 : }
1297 :
1298 14 : int nLGIDictId = AllocNewObject();
1299 14 : StartObj(nLGIDictId);
1300 14 : GDALPDFDictionaryRW oLGIDict;
1301 : oLGIDict.Add("Type", GDALPDFObjectRW::CreateName("LGIDict"))
1302 14 : .Add("Version", "2.1");
1303 14 : if( bHasGT )
1304 : {
1305 : double adfCTM[6];
1306 12 : double dfX1 = psMargins->nLeft;
1307 12 : double dfY2 = nHeight / dfUserUnit + psMargins->nBottom ;
1308 :
1309 12 : adfCTM[0] = adfGeoTransform[1] * dfUserUnit;
1310 12 : adfCTM[1] = adfGeoTransform[2] * dfUserUnit;
1311 12 : adfCTM[2] = - adfGeoTransform[4] * dfUserUnit;
1312 12 : adfCTM[3] = - adfGeoTransform[5] * dfUserUnit;
1313 12 : adfCTM[4] = adfGeoTransform[0] - (adfCTM[0] * dfX1 + adfCTM[2] * dfY2);
1314 12 : adfCTM[5] = adfGeoTransform[3] - (adfCTM[1] * dfX1 + adfCTM[3] * dfY2);
1315 :
1316 12 : oLGIDict.Add("CTM", &((new GDALPDFArrayRW())->Add(adfCTM, 6, TRUE)));
1317 : }
1318 : else
1319 : {
1320 2 : GDALPDFArrayRW* poRegistrationArray = new GDALPDFArrayRW();
1321 : int i;
1322 12 : for(i = 0; i < nGCPCount; i++)
1323 : {
1324 10 : GDALPDFArrayRW* poPTArray = new GDALPDFArrayRW();
1325 10 : poPTArray->Add(pasGCPList[i].dfGCPPixel / dfUserUnit + psMargins->nLeft, TRUE);
1326 10 : poPTArray->Add((nHeight - pasGCPList[i].dfGCPLine) / dfUserUnit + psMargins->nBottom, TRUE);
1327 10 : poPTArray->Add(pasGCPList[i].dfGCPX, TRUE);
1328 10 : poPTArray->Add(pasGCPList[i].dfGCPY, TRUE);
1329 10 : poRegistrationArray->Add(poPTArray);
1330 : }
1331 2 : oLGIDict.Add("Registration", poRegistrationArray);
1332 : }
1333 14 : if( poNeatLineArray )
1334 : {
1335 14 : oLGIDict.Add("Neatline", poNeatLineArray);
1336 : }
1337 :
1338 14 : const OGR_SRSNode* poNode = poSRS->GetRoot();
1339 14 : if( poNode != NULL )
1340 14 : poNode = poNode->GetChild(0);
1341 14 : const char* pszDescription = NULL;
1342 14 : if( poNode != NULL )
1343 14 : pszDescription = poNode->GetValue();
1344 14 : if( pszDescription )
1345 : {
1346 14 : oLGIDict.Add("Description", pszDescription);
1347 : }
1348 :
1349 14 : oLGIDict.Add("Projection", poProjectionDict);
1350 :
1351 : /* GDAL extension */
1352 14 : if( CSLTestBoolean( CPLGetConfigOption("GDAL_PDF_OGC_BP_WRITE_WKT", "TRUE") ) )
1353 6 : poProjectionDict->Add("WKT", pszWKT);
1354 :
1355 14 : VSIFPrintfL(fp, "%s\n", oLGIDict.Serialize().c_str());
1356 14 : EndObj();
1357 :
1358 14 : OSRDestroySpatialReference(hSRS);
1359 :
1360 14 : return nLGIDictId;
1361 : }
1362 :
1363 : /************************************************************************/
1364 : /* GDALPDFGetValueFromDSOrOption() */
1365 : /************************************************************************/
1366 :
1367 714 : static const char* GDALPDFGetValueFromDSOrOption(GDALDataset* poSrcDS,
1368 : char** papszOptions,
1369 : const char* pszKey)
1370 : {
1371 714 : const char* pszValue = CSLFetchNameValue(papszOptions, pszKey);
1372 714 : if (pszValue == NULL)
1373 702 : pszValue = poSrcDS->GetMetadataItem(pszKey);
1374 714 : if (pszValue != NULL && pszValue[0] == '\0')
1375 4 : return NULL;
1376 : else
1377 710 : return pszValue;
1378 : }
1379 :
1380 : /************************************************************************/
1381 : /* SetInfo() */
1382 : /************************************************************************/
1383 :
1384 102 : int GDALPDFWriter::SetInfo(GDALDataset* poSrcDS,
1385 : char** papszOptions)
1386 : {
1387 102 : const char* pszAUTHOR = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "AUTHOR");
1388 102 : const char* pszPRODUCER = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "PRODUCER");
1389 102 : const char* pszCREATOR = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "CREATOR");
1390 102 : const char* pszCREATION_DATE = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "CREATION_DATE");
1391 102 : const char* pszSUBJECT = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "SUBJECT");
1392 102 : const char* pszTITLE = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "TITLE");
1393 102 : const char* pszKEYWORDS = GDALPDFGetValueFromDSOrOption(poSrcDS, papszOptions, "KEYWORDS");
1394 :
1395 102 : if (pszAUTHOR == NULL && pszPRODUCER == NULL && pszCREATOR == NULL && pszCREATION_DATE == NULL &&
1396 : pszSUBJECT == NULL && pszTITLE == NULL && pszKEYWORDS == NULL)
1397 90 : return 0;
1398 :
1399 12 : if (nInfoId == 0)
1400 8 : nInfoId = AllocNewObject();
1401 12 : StartObj(nInfoId, nInfoGen);
1402 12 : GDALPDFDictionaryRW oDict;
1403 12 : if (pszAUTHOR != NULL)
1404 12 : oDict.Add("Author", pszAUTHOR);
1405 12 : if (pszPRODUCER != NULL)
1406 4 : oDict.Add("Producer", pszPRODUCER);
1407 12 : if (pszCREATOR != NULL)
1408 4 : oDict.Add("Creator", pszCREATOR);
1409 12 : if (pszCREATION_DATE != NULL)
1410 0 : oDict.Add("CreationDate", pszCREATION_DATE);
1411 12 : if (pszSUBJECT != NULL)
1412 4 : oDict.Add("Subject", pszSUBJECT);
1413 12 : if (pszTITLE != NULL)
1414 4 : oDict.Add("Title", pszTITLE);
1415 12 : if (pszKEYWORDS != NULL)
1416 4 : oDict.Add("Keywords", pszKEYWORDS);
1417 12 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
1418 12 : EndObj();
1419 :
1420 12 : return nInfoId;
1421 : }
1422 :
1423 : /************************************************************************/
1424 : /* SetXMP() */
1425 : /************************************************************************/
1426 :
1427 102 : int GDALPDFWriter::SetXMP(GDALDataset* poSrcDS,
1428 : const char* pszXMP)
1429 : {
1430 102 : if (pszXMP != NULL && EQUALN(pszXMP, "NO", 2))
1431 2 : return 0;
1432 100 : if (pszXMP != NULL && pszXMP[0] == '\0')
1433 0 : return 0;
1434 :
1435 100 : char** papszXMP = poSrcDS->GetMetadata("xml:XMP");
1436 100 : if (pszXMP == NULL && papszXMP != NULL && papszXMP[0] != NULL)
1437 10 : pszXMP = papszXMP[0];
1438 :
1439 100 : if (pszXMP == NULL)
1440 90 : return 0;
1441 :
1442 10 : CPLXMLNode* psNode = CPLParseXMLString(pszXMP);
1443 10 : if (psNode == NULL)
1444 0 : return 0;
1445 10 : CPLDestroyXMLNode(psNode);
1446 :
1447 10 : if(nXMPId == 0)
1448 6 : nXMPId = AllocNewObject();
1449 10 : StartObj(nXMPId, nXMPGen);
1450 10 : GDALPDFDictionaryRW oDict;
1451 : oDict.Add("Type", GDALPDFObjectRW::CreateName("Metadata"))
1452 : .Add("Subtype", GDALPDFObjectRW::CreateName("XML"))
1453 10 : .Add("Length", (int)strlen(pszXMP));
1454 10 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
1455 10 : VSIFPrintfL(fp, "stream\n");
1456 10 : VSIFPrintfL(fp, "%s\n", pszXMP);
1457 10 : VSIFPrintfL(fp, "endstream\n");
1458 10 : EndObj();
1459 10 : return nXMPId;
1460 : }
1461 :
1462 : /************************************************************************/
1463 : /* WriteOCG() */
1464 : /************************************************************************/
1465 :
1466 188 : int GDALPDFWriter::WriteOCG(const char* pszLayerName, int nParentId)
1467 : {
1468 188 : if (pszLayerName == NULL || pszLayerName[0] == '\0')
1469 178 : return 0;
1470 :
1471 10 : int nOGCId = AllocNewObject();
1472 :
1473 : GDALPDFOCGDesc oOCGDesc;
1474 10 : oOCGDesc.nId = nOGCId;
1475 10 : oOCGDesc.nParentId = nParentId;
1476 :
1477 10 : asOCGs.push_back(oOCGDesc);
1478 :
1479 10 : StartObj(nOGCId);
1480 : {
1481 10 : GDALPDFDictionaryRW oDict;
1482 10 : oDict.Add("Type", GDALPDFObjectRW::CreateName("OCG"));
1483 10 : oDict.Add("Name", pszLayerName);
1484 10 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
1485 : }
1486 10 : EndObj();
1487 :
1488 10 : return nOGCId;
1489 : }
1490 :
1491 : /************************************************************************/
1492 : /* StartPage() */
1493 : /************************************************************************/
1494 :
1495 92 : int GDALPDFWriter::StartPage(GDALDataset* poSrcDS,
1496 : double dfDPI,
1497 : const char* pszGEO_ENCODING,
1498 : const char* pszNEATLINE,
1499 : PDFMargins* psMargins,
1500 : PDFCompressMethod eStreamCompressMethod,
1501 : int bHasOGRData)
1502 : {
1503 92 : int nWidth = poSrcDS->GetRasterXSize();
1504 92 : int nHeight = poSrcDS->GetRasterYSize();
1505 92 : int nBands = poSrcDS->GetRasterCount();
1506 :
1507 92 : double dfUserUnit = dfDPI / 72.0;
1508 92 : double dfWidthInUserUnit = nWidth / dfUserUnit + psMargins->nLeft + psMargins->nRight;
1509 92 : double dfHeightInUserUnit = nHeight / dfUserUnit + psMargins->nBottom + psMargins->nTop;
1510 :
1511 92 : int nPageId = AllocNewObject();
1512 92 : asPageId.push_back(nPageId);
1513 :
1514 92 : int nContentId = AllocNewObject();
1515 92 : int nResourcesId = AllocNewObject();
1516 :
1517 : int bISO32000 = EQUAL(pszGEO_ENCODING, "ISO32000") ||
1518 92 : EQUAL(pszGEO_ENCODING, "BOTH");
1519 : int bOGC_BP = EQUAL(pszGEO_ENCODING, "OGC_BP") ||
1520 92 : EQUAL(pszGEO_ENCODING, "BOTH");
1521 :
1522 92 : int nViewportId = 0;
1523 92 : if( bISO32000 )
1524 76 : nViewportId = WriteSRS_ISO32000(poSrcDS, dfUserUnit, pszNEATLINE, psMargins);
1525 :
1526 92 : int nLGIDictId = 0;
1527 92 : if( bOGC_BP )
1528 12 : nLGIDictId = WriteSRS_OGC_BP(poSrcDS, dfUserUnit, pszNEATLINE, psMargins);
1529 :
1530 92 : StartObj(nPageId);
1531 92 : GDALPDFDictionaryRW oDictPage;
1532 : oDictPage.Add("Type", GDALPDFObjectRW::CreateName("Page"))
1533 : .Add("Parent", nPageResourceId, 0)
1534 : .Add("MediaBox", &((new GDALPDFArrayRW())
1535 : ->Add(0).Add(0).Add(dfWidthInUserUnit).Add(dfHeightInUserUnit)))
1536 : .Add("UserUnit", dfUserUnit)
1537 : .Add("Contents", nContentId, 0)
1538 92 : .Add("Resources", nResourcesId, 0);
1539 :
1540 92 : if (nBands == 4)
1541 : {
1542 : oDictPage.Add("Group",
1543 : &((new GDALPDFDictionaryRW())
1544 : ->Add("Type", GDALPDFObjectRW::CreateName("Group"))
1545 : .Add("S", GDALPDFObjectRW::CreateName("Transparency"))
1546 6 : .Add("CS", GDALPDFObjectRW::CreateName("DeviceRGB"))));
1547 : }
1548 92 : if (nViewportId)
1549 : {
1550 : oDictPage.Add("VP", &((new GDALPDFArrayRW())
1551 68 : ->Add(nViewportId, 0)));
1552 : }
1553 92 : if (nLGIDictId)
1554 : {
1555 12 : oDictPage.Add("LGIDict", nLGIDictId, 0);
1556 : }
1557 :
1558 92 : if (bHasOGRData)
1559 4 : oDictPage.Add("StructParents", 0);
1560 :
1561 92 : VSIFPrintfL(fp, "%s\n", oDictPage.Serialize().c_str());
1562 92 : EndObj();
1563 :
1564 92 : oPageContext.poSrcDS = poSrcDS;
1565 92 : oPageContext.nPageId = nPageId;
1566 92 : oPageContext.nContentId = nContentId;
1567 92 : oPageContext.nResourcesId = nResourcesId;
1568 92 : oPageContext.dfDPI = dfDPI;
1569 92 : oPageContext.sMargins = *psMargins;
1570 92 : oPageContext.nOCGRasterId = 0;
1571 92 : oPageContext.eStreamCompressMethod = eStreamCompressMethod;
1572 :
1573 92 : return TRUE;
1574 : }
1575 :
1576 : /************************************************************************/
1577 : /* WriteColorTable() */
1578 : /************************************************************************/
1579 :
1580 92 : int GDALPDFWriter::WriteColorTable(GDALDataset* poSrcDS)
1581 : {
1582 : /* Does the source image has a color table ? */
1583 92 : GDALColorTable* poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
1584 92 : int nColorTableId = 0;
1585 92 : if (poCT != NULL && poCT->GetColorEntryCount() <= 256)
1586 : {
1587 2 : int nColors = poCT->GetColorEntryCount();
1588 2 : nColorTableId = AllocNewObject();
1589 :
1590 2 : int nLookupTableId = AllocNewObject();
1591 :
1592 : /* Index object */
1593 2 : StartObj(nColorTableId);
1594 : {
1595 2 : GDALPDFArrayRW oArray;
1596 : oArray.Add(GDALPDFObjectRW::CreateName("Indexed"))
1597 : .Add(&((new GDALPDFArrayRW())->Add(GDALPDFObjectRW::CreateName("DeviceRGB"))))
1598 : .Add(nColors-1)
1599 2 : .Add(nLookupTableId, 0);
1600 2 : VSIFPrintfL(fp, "%s\n", oArray.Serialize().c_str());
1601 : }
1602 2 : EndObj();
1603 :
1604 : /* Lookup table object */
1605 2 : StartObj(nLookupTableId);
1606 : {
1607 2 : GDALPDFDictionaryRW oDict;
1608 2 : oDict.Add("Length", nColors * 3);
1609 2 : VSIFPrintfL(fp, "%s %% Lookup table\n", oDict.Serialize().c_str());
1610 : }
1611 2 : VSIFPrintfL(fp, "stream\n");
1612 : GByte pabyLookup[768];
1613 34 : for(int i=0;i<nColors;i++)
1614 : {
1615 32 : const GDALColorEntry* poEntry = poCT->GetColorEntry(i);
1616 32 : pabyLookup[3 * i + 0] = (GByte)poEntry->c1;
1617 32 : pabyLookup[3 * i + 1] = (GByte)poEntry->c2;
1618 32 : pabyLookup[3 * i + 2] = (GByte)poEntry->c3;
1619 : }
1620 2 : VSIFWriteL(pabyLookup, 3 * nColors, 1, fp);
1621 2 : VSIFPrintfL(fp, "\n");
1622 2 : VSIFPrintfL(fp, "endstream\n");
1623 2 : EndObj();
1624 : }
1625 :
1626 92 : return nColorTableId;
1627 : }
1628 :
1629 : /************************************************************************/
1630 : /* WriteImagery() */
1631 : /************************************************************************/
1632 :
1633 90 : int GDALPDFWriter::WriteImagery(const char* pszLayerName,
1634 : PDFCompressMethod eCompressMethod,
1635 : int nPredictor,
1636 : int nJPEGQuality,
1637 : const char* pszJPEG2000_DRIVER,
1638 : int nBlockXSize, int nBlockYSize,
1639 : GDALProgressFunc pfnProgress,
1640 : void * pProgressData)
1641 : {
1642 90 : GDALDataset* poSrcDS = oPageContext.poSrcDS;
1643 90 : int nWidth = poSrcDS->GetRasterXSize();
1644 90 : int nHeight = poSrcDS->GetRasterYSize();
1645 90 : double dfUserUnit = oPageContext.dfDPI / 72.0;
1646 :
1647 90 : oPageContext.nOCGRasterId = WriteOCG(pszLayerName);
1648 :
1649 : /* Does the source image has a color table ? */
1650 90 : int nColorTableId = WriteColorTable(poSrcDS);
1651 :
1652 90 : int nXBlocks = (nWidth + nBlockXSize - 1) / nBlockXSize;
1653 90 : int nYBlocks = (nHeight + nBlockYSize - 1) / nBlockYSize;
1654 90 : int nBlocks = nXBlocks * nYBlocks;
1655 : int nBlockXOff, nBlockYOff;
1656 188 : for(nBlockYOff = 0; nBlockYOff < nYBlocks; nBlockYOff ++)
1657 : {
1658 224 : for(nBlockXOff = 0; nBlockXOff < nXBlocks; nBlockXOff ++)
1659 : {
1660 126 : int nReqWidth = MIN(nBlockXSize, nWidth - nBlockXOff * nBlockXSize);
1661 126 : int nReqHeight = MIN(nBlockYSize, nHeight - nBlockYOff * nBlockYSize);
1662 126 : int iImage = nBlockYOff * nXBlocks + nBlockXOff;
1663 :
1664 : void* pScaledData = GDALCreateScaledProgress( iImage / (double)nBlocks,
1665 : (iImage + 1) / (double)nBlocks,
1666 126 : pfnProgress, pProgressData);
1667 :
1668 : int nImageId = WriteBlock(poSrcDS,
1669 : nBlockXOff * nBlockXSize,
1670 : nBlockYOff * nBlockYSize,
1671 : nReqWidth, nReqHeight,
1672 : nColorTableId,
1673 : eCompressMethod,
1674 : nPredictor,
1675 : nJPEGQuality,
1676 : pszJPEG2000_DRIVER,
1677 : GDALScaledProgress,
1678 126 : pScaledData);
1679 :
1680 126 : GDALDestroyScaledProgress(pScaledData);
1681 :
1682 126 : if (nImageId == 0)
1683 0 : return FALSE;
1684 :
1685 : GDALPDFImageDesc oImageDesc;
1686 126 : oImageDesc.nImageId = nImageId;
1687 126 : oImageDesc.dfXOff = (nBlockXOff * nBlockXSize) / dfUserUnit + oPageContext.sMargins.nLeft;
1688 126 : oImageDesc.dfYOff = (nHeight - nBlockYOff * nBlockYSize - nReqHeight) / dfUserUnit + oPageContext.sMargins.nBottom;
1689 126 : oImageDesc.dfXSize = nReqWidth / dfUserUnit;
1690 126 : oImageDesc.dfYSize = nReqHeight / dfUserUnit;
1691 :
1692 126 : oPageContext.asImageDesc.push_back(oImageDesc);
1693 : }
1694 : }
1695 :
1696 90 : return TRUE;
1697 : }
1698 :
1699 : #ifdef OGR_ENABLED
1700 :
1701 : /************************************************************************/
1702 : /* WriteOGRDataSource() */
1703 : /************************************************************************/
1704 :
1705 2 : int GDALPDFWriter::WriteOGRDataSource(const char* pszOGRDataSource,
1706 : const char* pszOGRDisplayField,
1707 : const char* pszOGRDisplayLayerNames,
1708 : int bWriteOGRAttributes)
1709 : {
1710 2 : if (OGRGetDriverCount() == 0)
1711 0 : OGRRegisterAll();
1712 :
1713 2 : OGRDataSourceH hDS = OGROpen(pszOGRDataSource, 0, NULL);
1714 2 : if (hDS == NULL)
1715 0 : return FALSE;
1716 :
1717 2 : int iObj = 0;
1718 :
1719 2 : int nLayers = OGR_DS_GetLayerCount(hDS);
1720 :
1721 2 : char** papszLayerNames = CSLTokenizeString2(pszOGRDisplayLayerNames,",",0);
1722 :
1723 4 : for(int iLayer = 0; iLayer < nLayers; iLayer ++)
1724 : {
1725 2 : CPLString osLayerName;
1726 2 : if (CSLCount(papszLayerNames) < nLayers)
1727 0 : osLayerName = CPLSPrintf("Layer%d", iLayer + 1);
1728 : else
1729 2 : osLayerName = papszLayerNames[iLayer];
1730 :
1731 : WriteOGRLayer(hDS, iLayer,
1732 : pszOGRDisplayField,
1733 : osLayerName,
1734 : bWriteOGRAttributes,
1735 2 : iObj);
1736 : }
1737 :
1738 2 : OGRReleaseDataSource(hDS);
1739 :
1740 2 : CSLDestroy(papszLayerNames);
1741 :
1742 2 : return TRUE;
1743 : }
1744 :
1745 : /************************************************************************/
1746 : /* StartOGRLayer() */
1747 : /************************************************************************/
1748 :
1749 4 : GDALPDFLayerDesc GDALPDFWriter::StartOGRLayer(CPLString osLayerName,
1750 : int bWriteOGRAttributes)
1751 : {
1752 4 : GDALPDFLayerDesc osVectorDesc;
1753 4 : osVectorDesc.osLayerName = osLayerName;
1754 4 : osVectorDesc.bWriteOGRAttributes = bWriteOGRAttributes;
1755 4 : osVectorDesc.nOGCId = WriteOCG(osLayerName);
1756 4 : osVectorDesc.nFeatureLayerId = (bWriteOGRAttributes) ? AllocNewObject() : 0;
1757 4 : osVectorDesc.nOCGTextId = 0;
1758 :
1759 0 : return osVectorDesc;
1760 : }
1761 :
1762 : /************************************************************************/
1763 : /* EndOGRLayer() */
1764 : /************************************************************************/
1765 :
1766 4 : void GDALPDFWriter::EndOGRLayer(GDALPDFLayerDesc& osVectorDesc)
1767 : {
1768 4 : if (osVectorDesc.bWriteOGRAttributes)
1769 : {
1770 4 : StartObj(osVectorDesc.nFeatureLayerId);
1771 :
1772 4 : GDALPDFDictionaryRW oDict;
1773 : oDict.Add("A", &(new GDALPDFDictionaryRW())->Add("O",
1774 4 : GDALPDFObjectRW::CreateName("UserProperties")));
1775 :
1776 4 : GDALPDFArrayRW* poArray = new GDALPDFArrayRW();
1777 4 : oDict.Add("K", poArray);
1778 :
1779 18 : for(int i = 0; i < (int)osVectorDesc.aUserPropertiesIds.size(); i++)
1780 : {
1781 14 : poArray->Add(osVectorDesc.aUserPropertiesIds[i], 0);
1782 : }
1783 :
1784 4 : if (nStructTreeRootId == 0)
1785 4 : nStructTreeRootId = AllocNewObject();
1786 :
1787 4 : oDict.Add("P", nStructTreeRootId, 0);
1788 4 : oDict.Add("S", GDALPDFObjectRW::CreateName(osVectorDesc.osLayerName));
1789 :
1790 4 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
1791 :
1792 4 : EndObj();
1793 : }
1794 :
1795 4 : oPageContext.asVectorDesc.push_back(osVectorDesc);
1796 4 : }
1797 :
1798 : /************************************************************************/
1799 : /* WriteOGRLayer() */
1800 : /************************************************************************/
1801 :
1802 2 : int GDALPDFWriter::WriteOGRLayer(OGRDataSourceH hDS,
1803 : int iLayer,
1804 : const char* pszOGRDisplayField,
1805 : CPLString osLayerName,
1806 : int bWriteOGRAttributes,
1807 : int& iObj)
1808 : {
1809 : GDALPDFLayerDesc osVectorDesc = StartOGRLayer(osLayerName,
1810 2 : bWriteOGRAttributes);
1811 2 : OGRLayerH hLyr = OGR_DS_GetLayer(hDS, iLayer);
1812 :
1813 : OGRFeatureH hFeat;
1814 2 : int iObjLayer = 0;
1815 10 : while( (hFeat = OGR_L_GetNextFeature(hLyr)) != NULL)
1816 : {
1817 : WriteOGRFeature(osVectorDesc,
1818 : hFeat,
1819 : pszOGRDisplayField,
1820 : bWriteOGRAttributes,
1821 : iObj,
1822 6 : iObjLayer);
1823 :
1824 6 : OGR_F_Destroy(hFeat);
1825 : }
1826 :
1827 2 : EndOGRLayer(osVectorDesc);
1828 :
1829 2 : return TRUE;
1830 : }
1831 :
1832 : /************************************************************************/
1833 : /* DrawGeometry() */
1834 : /************************************************************************/
1835 :
1836 26 : static void DrawGeometry(VSILFILE* fp, OGRGeometryH hGeom, double adfMatrix[4], int bPaint = TRUE)
1837 : {
1838 26 : switch(wkbFlatten(OGR_G_GetGeometryType(hGeom)))
1839 : {
1840 : case wkbLineString:
1841 : {
1842 16 : int nPoints = OGR_G_GetPointCount(hGeom);
1843 84 : for(int i=0;i<nPoints;i++)
1844 : {
1845 68 : double dfX = OGR_G_GetX(hGeom, i) * adfMatrix[1] + adfMatrix[0];
1846 68 : double dfY = OGR_G_GetY(hGeom, i) * adfMatrix[3] + adfMatrix[2];
1847 68 : VSIFPrintfL(fp, "%f %f %c\n", dfX, dfY, (i == 0) ? 'm' : 'l');
1848 : }
1849 16 : if (bPaint)
1850 4 : VSIFPrintfL(fp, "S\n");
1851 16 : break;
1852 : }
1853 :
1854 : case wkbPolygon:
1855 : {
1856 8 : int nParts = OGR_G_GetGeometryCount(hGeom);
1857 20 : for(int i=0;i<nParts;i++)
1858 : {
1859 12 : DrawGeometry(fp, OGR_G_GetGeometryRef(hGeom, i), adfMatrix, FALSE);
1860 12 : VSIFPrintfL(fp, "h\n");
1861 : }
1862 8 : if (bPaint)
1863 4 : VSIFPrintfL(fp, "b*\n");
1864 8 : break;
1865 : }
1866 :
1867 : case wkbMultiLineString:
1868 : {
1869 0 : int nParts = OGR_G_GetGeometryCount(hGeom);
1870 0 : for(int i=0;i<nParts;i++)
1871 : {
1872 0 : DrawGeometry(fp, OGR_G_GetGeometryRef(hGeom, i), adfMatrix, FALSE);
1873 : }
1874 0 : if (bPaint)
1875 0 : VSIFPrintfL(fp, "S\n");
1876 0 : break;
1877 : }
1878 :
1879 : case wkbMultiPolygon:
1880 : {
1881 2 : int nParts = OGR_G_GetGeometryCount(hGeom);
1882 6 : for(int i=0;i<nParts;i++)
1883 : {
1884 4 : DrawGeometry(fp, OGR_G_GetGeometryRef(hGeom, i), adfMatrix, FALSE);
1885 : }
1886 2 : if (bPaint)
1887 2 : VSIFPrintfL(fp, "b*\n");
1888 : break;
1889 : }
1890 :
1891 : default:
1892 : break;
1893 : }
1894 26 : }
1895 :
1896 : /************************************************************************/
1897 : /* WriteOGRFeature() */
1898 : /************************************************************************/
1899 :
1900 14 : int GDALPDFWriter::WriteOGRFeature(GDALPDFLayerDesc& osVectorDesc,
1901 : OGRFeatureH hFeat,
1902 : const char* pszOGRDisplayField,
1903 : int bWriteOGRAttributes,
1904 : int& iObj,
1905 : int& iObjLayer)
1906 : {
1907 14 : GDALDataset* poSrcDS = oPageContext.poSrcDS;
1908 14 : int nHeight = poSrcDS->GetRasterYSize();
1909 14 : double dfUserUnit = oPageContext.dfDPI / 72.0;
1910 : double adfGeoTransform[6];
1911 14 : poSrcDS->GetGeoTransform(adfGeoTransform);
1912 :
1913 : double adfMatrix[4];
1914 14 : adfMatrix[0] = - adfGeoTransform[0] / (adfGeoTransform[1] * dfUserUnit) + oPageContext.sMargins.nLeft;
1915 14 : adfMatrix[1] = 1.0 / (adfGeoTransform[1] * dfUserUnit);
1916 14 : adfMatrix[2] = - (adfGeoTransform[3] + adfGeoTransform[5] * nHeight) / (-adfGeoTransform[5] * dfUserUnit) + oPageContext.sMargins.nBottom;
1917 14 : adfMatrix[3] = 1.0 / (-adfGeoTransform[5] * dfUserUnit);
1918 :
1919 14 : double dfRadius = 5 * dfUserUnit;
1920 :
1921 14 : OGRGeometryH hGeom = OGR_F_GetGeometryRef(hFeat);
1922 14 : if (hGeom == NULL)
1923 : {
1924 0 : return TRUE;
1925 : }
1926 :
1927 : /* -------------------------------------------------------------- */
1928 : /* Get envelope */
1929 : /* -------------------------------------------------------------- */
1930 14 : OGREnvelope sEnvelope;
1931 14 : OGR_G_GetEnvelope(hGeom, &sEnvelope);
1932 :
1933 :
1934 : /* -------------------------------------------------------------- */
1935 : /* Get style */
1936 : /* -------------------------------------------------------------- */
1937 14 : int nPenR = 0, nPenG = 0, nPenB = 0, nPenA = 255;
1938 14 : int nBrushR = 127, nBrushG = 127, nBrushB = 127, nBrushA = 127;
1939 14 : int nTextR = 0, nTextG = 0, nTextB = 0, nTextA = 255;
1940 14 : double dfTextSize = 12, dfTextAngle = 0;
1941 14 : double dfPenWidth = 1;
1942 14 : CPLString osDashArray;
1943 14 : CPLString osLabelText;
1944 :
1945 14 : OGRStyleMgrH hSM = OGR_SM_Create(NULL);
1946 14 : OGR_SM_InitFromFeature(hSM, hFeat);
1947 14 : int nCount = OGR_SM_GetPartCount(hSM, NULL);
1948 24 : for(int iPart = 0; iPart < nCount; iPart++)
1949 : {
1950 10 : OGRStyleToolH hTool = OGR_SM_GetPart(hSM, iPart, NULL);
1951 10 : if (hTool)
1952 : {
1953 8 : if (OGR_ST_GetType(hTool) == OGRSTCPen)
1954 : {
1955 4 : int bIsNull = TRUE;
1956 4 : const char* pszColor = OGR_ST_GetParamStr(hTool, OGRSTPenColor, &bIsNull);
1957 4 : if (pszColor && !bIsNull)
1958 : {
1959 4 : int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 255;
1960 4 : int nVals = sscanf(pszColor,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue,&nAlpha);
1961 4 : if (nVals >= 3)
1962 : {
1963 4 : nPenR = nRed;
1964 4 : nPenG = nGreen;
1965 4 : nPenB = nBlue;
1966 4 : if (nVals == 4)
1967 0 : nPenA = nAlpha;
1968 : }
1969 : }
1970 :
1971 4 : const char* pszDash = OGR_ST_GetParamStr(hTool, OGRSTPenPattern, &bIsNull);
1972 4 : if (pszDash && !bIsNull)
1973 : {
1974 2 : char** papszTokens = CSLTokenizeString2(pszDash, " ", 0);
1975 2 : int nTokens = CSLCount(papszTokens);
1976 2 : if ((nTokens % 2) == 0)
1977 : {
1978 6 : for(int i=0;i<nTokens;i++)
1979 : {
1980 4 : osDashArray += CPLSPrintf("%d ", atoi(papszTokens[i]));
1981 : }
1982 : }
1983 2 : CSLDestroy(papszTokens);
1984 : }
1985 :
1986 : //OGRSTUnitId eUnit = OGR_ST_GetUnit(hTool);
1987 4 : double dfWidth = OGR_ST_GetParamDbl(hTool, OGRSTPenWidth, &bIsNull);
1988 4 : if (!bIsNull)
1989 4 : dfPenWidth = dfWidth;
1990 : }
1991 4 : else if (OGR_ST_GetType(hTool) == OGRSTCBrush)
1992 : {
1993 : int bIsNull;
1994 2 : const char* pszColor = OGR_ST_GetParamStr(hTool, OGRSTBrushFColor, &bIsNull);
1995 2 : if (pszColor)
1996 : {
1997 2 : int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 255;
1998 2 : int nVals = sscanf(pszColor,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue,&nAlpha);
1999 2 : if (nVals >= 3)
2000 : {
2001 2 : nBrushR = nRed;
2002 2 : nBrushG = nGreen;
2003 2 : nBrushB = nBlue;
2004 2 : if (nVals == 4)
2005 0 : nBrushA = nAlpha;
2006 : }
2007 : }
2008 : }
2009 2 : else if (OGR_ST_GetType(hTool) == OGRSTCLabel)
2010 : {
2011 : int bIsNull;
2012 2 : const char* pszStr = OGR_ST_GetParamStr(hTool, OGRSTLabelTextString, &bIsNull);
2013 2 : if (pszStr)
2014 : {
2015 2 : osLabelText = pszStr;
2016 : }
2017 :
2018 2 : const char* pszColor = OGR_ST_GetParamStr(hTool, OGRSTLabelFColor, &bIsNull);
2019 2 : if (pszColor && !bIsNull)
2020 : {
2021 2 : int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 255;
2022 2 : int nVals = sscanf(pszColor,"#%2x%2x%2x%2x",&nRed,&nGreen,&nBlue,&nAlpha);
2023 2 : if (nVals >= 3)
2024 : {
2025 2 : nTextR = nRed;
2026 2 : nTextG = nGreen;
2027 2 : nTextB = nBlue;
2028 2 : if (nVals == 4)
2029 2 : nTextA = nAlpha;
2030 : }
2031 : }
2032 :
2033 2 : double dfVal = OGR_ST_GetParamDbl(hTool, OGRSTLabelSize, &bIsNull);
2034 2 : if (!bIsNull)
2035 : {
2036 2 : dfTextSize = dfVal;
2037 : }
2038 :
2039 2 : dfVal = OGR_ST_GetParamDbl(hTool, OGRSTLabelAngle, &bIsNull);
2040 2 : if (!bIsNull)
2041 : {
2042 2 : dfTextAngle = dfVal;
2043 : }
2044 : }
2045 8 : OGR_ST_Destroy(hTool);
2046 : }
2047 : }
2048 14 : OGR_SM_Destroy(hSM);
2049 :
2050 : /* -------------------------------------------------------------- */
2051 : /* Write object dictionary */
2052 : /* -------------------------------------------------------------- */
2053 14 : int nObjectId = AllocNewObject();
2054 14 : int nObjectLengthId = AllocNewObject();
2055 :
2056 14 : osVectorDesc.aIds.push_back(nObjectId);
2057 :
2058 14 : StartObj(nObjectId);
2059 :
2060 : {
2061 14 : GDALPDFDictionaryRW oDict;
2062 14 : double dfMargin = (wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint) ? dfRadius + dfPenWidth : dfPenWidth;
2063 : oDict.Add("Length", nObjectLengthId, 0)
2064 : .Add("Type", GDALPDFObjectRW::CreateName("XObject"))
2065 : .Add("BBox", &((new GDALPDFArrayRW())
2066 28 : ->Add((int)floor(sEnvelope.MinX * adfMatrix[1] + adfMatrix[0] - dfMargin)).
2067 28 : Add((int)floor(sEnvelope.MinY * adfMatrix[3] + adfMatrix[2] - dfMargin)).
2068 28 : Add((int)ceil(sEnvelope.MaxX * adfMatrix[1] + adfMatrix[0] + dfMargin)).
2069 28 : Add((int)ceil(sEnvelope.MaxY * adfMatrix[3] + adfMatrix[2] + dfMargin))))
2070 126 : .Add("Subtype", GDALPDFObjectRW::CreateName("Form"));
2071 14 : if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
2072 : {
2073 14 : oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
2074 : }
2075 :
2076 14 : GDALPDFDictionaryRW* poGS1 = new GDALPDFDictionaryRW();
2077 28 : poGS1->Add("Type", GDALPDFObjectRW::CreateName("ExtGState"));
2078 14 : if (nPenA != 255)
2079 0 : poGS1->Add("CA", (nPenA == 127 || nPenA == 128) ? 0.5 : nPenA / 255.0);
2080 14 : if (nBrushA != 255)
2081 14 : poGS1->Add("ca", (nBrushA == 127 || nBrushA == 128) ? 0.5 : nBrushA / 255.0 );
2082 :
2083 14 : GDALPDFDictionaryRW* poExtGState = new GDALPDFDictionaryRW();
2084 14 : poExtGState->Add("GS1", poGS1);
2085 :
2086 14 : GDALPDFDictionaryRW* poResources = new GDALPDFDictionaryRW();
2087 14 : poResources->Add("ExtGState", poExtGState);
2088 :
2089 14 : oDict.Add("Resources", poResources);
2090 :
2091 14 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
2092 : }
2093 :
2094 : /* -------------------------------------------------------------- */
2095 : /* Write object stream */
2096 : /* -------------------------------------------------------------- */
2097 14 : VSIFPrintfL(fp, "stream\n");
2098 :
2099 14 : vsi_l_offset nStreamStart = VSIFTellL(fp);
2100 :
2101 14 : VSILFILE* fpGZip = NULL;
2102 14 : VSILFILE* fpBack = fp;
2103 14 : if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
2104 : {
2105 14 : fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
2106 14 : fp = fpGZip;
2107 : }
2108 :
2109 14 : VSIFPrintfL(fp, "q\n");
2110 :
2111 14 : VSIFPrintfL(fp, "/GS1 gs\n");
2112 :
2113 : VSIFPrintfL(fp, "%f w\n"
2114 : "0 J\n"
2115 : "0 j\n"
2116 : "10 M\n"
2117 : "[%s]0 d\n",
2118 : dfPenWidth,
2119 14 : osDashArray.c_str());
2120 :
2121 14 : VSIFPrintfL(fp, "%f %f %f RG\n", nPenR / 255.0, nPenG / 255.0, nPenB / 255.0);
2122 14 : VSIFPrintfL(fp, "%f %f %f rg\n", nBrushR / 255.0, nBrushG / 255.0, nBrushB / 255.0);
2123 :
2124 14 : if (wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint)
2125 : {
2126 4 : double dfX = OGR_G_GetX(hGeom, 0) * adfMatrix[1] + adfMatrix[0];
2127 4 : double dfY = OGR_G_GetY(hGeom, 0) * adfMatrix[3] + adfMatrix[2];
2128 :
2129 : /* See http://www.whizkidtech.redprince.net/bezier/circle/kappa/ */
2130 4 : const double dfKappa = 0.5522847498;
2131 :
2132 4 : VSIFPrintfL(fp, "%f %f m\n", dfX - dfRadius, dfY);
2133 : VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
2134 : dfX - dfRadius, dfY - dfRadius * dfKappa,
2135 : dfX - dfRadius * dfKappa, dfY - dfRadius,
2136 4 : dfX, dfY - dfRadius);
2137 : VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
2138 : dfX + dfRadius * dfKappa, dfY - dfRadius,
2139 : dfX + dfRadius, dfY - dfRadius * dfKappa,
2140 4 : dfX + dfRadius, dfY);
2141 : VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
2142 : dfX + dfRadius, dfY + dfRadius * dfKappa,
2143 : dfX + dfRadius * dfKappa, dfY + dfRadius,
2144 4 : dfX, dfY + dfRadius);
2145 : VSIFPrintfL(fp, "%f %f %f %f %f %f c\n",
2146 : dfX - dfRadius * dfKappa, dfY + dfRadius,
2147 : dfX - dfRadius, dfY + dfRadius * dfKappa,
2148 4 : dfX - dfRadius, dfY);
2149 4 : VSIFPrintfL(fp, "b*\n");
2150 : }
2151 : else
2152 : {
2153 10 : DrawGeometry(fp, hGeom, adfMatrix);
2154 : }
2155 :
2156 14 : VSIFPrintfL(fp, "Q");
2157 :
2158 14 : if (fpGZip)
2159 14 : VSIFCloseL(fpGZip);
2160 14 : fp = fpBack;
2161 :
2162 14 : vsi_l_offset nStreamEnd = VSIFTellL(fp);
2163 14 : VSIFPrintfL(fp, "\n");
2164 14 : VSIFPrintfL(fp, "endstream\n");
2165 14 : EndObj();
2166 :
2167 14 : StartObj(nObjectLengthId);
2168 : VSIFPrintfL(fp,
2169 : " %ld\n",
2170 14 : (long)(nStreamEnd - nStreamStart));
2171 14 : EndObj();
2172 :
2173 : /* -------------------------------------------------------------- */
2174 : /* Write label */
2175 : /* -------------------------------------------------------------- */
2176 14 : if (osLabelText.size() && wkbFlatten(OGR_G_GetGeometryType(hGeom)) == wkbPoint)
2177 : {
2178 2 : if (osVectorDesc.nOCGTextId == 0)
2179 2 : osVectorDesc.nOCGTextId = WriteOCG("Text", osVectorDesc.nOGCId);
2180 :
2181 : /* -------------------------------------------------------------- */
2182 : /* Write object dictionary */
2183 : /* -------------------------------------------------------------- */
2184 2 : nObjectId = AllocNewObject();
2185 2 : nObjectLengthId = AllocNewObject();
2186 :
2187 2 : osVectorDesc.aIdsText.push_back(nObjectId);
2188 :
2189 2 : StartObj(nObjectId);
2190 : {
2191 2 : GDALPDFDictionaryRW oDict;
2192 :
2193 2 : GDALDataset* poSrcDS = oPageContext.poSrcDS;
2194 2 : int nWidth = poSrcDS->GetRasterXSize();
2195 2 : int nHeight = poSrcDS->GetRasterYSize();
2196 2 : double dfUserUnit = oPageContext.dfDPI / 72.0;
2197 2 : double dfWidthInUserUnit = nWidth / dfUserUnit + oPageContext.sMargins.nLeft + oPageContext.sMargins.nRight;
2198 2 : double dfHeightInUserUnit = nHeight / dfUserUnit + oPageContext.sMargins.nBottom + oPageContext.sMargins.nTop;
2199 :
2200 : oDict.Add("Length", nObjectLengthId, 0)
2201 : .Add("Type", GDALPDFObjectRW::CreateName("XObject"))
2202 : .Add("BBox", &((new GDALPDFArrayRW())
2203 : ->Add(0).Add(0)).Add(dfWidthInUserUnit).Add(dfHeightInUserUnit))
2204 2 : .Add("Subtype", GDALPDFObjectRW::CreateName("Form"));
2205 2 : if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
2206 : {
2207 2 : oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
2208 : }
2209 :
2210 2 : GDALPDFDictionaryRW* poResources = new GDALPDFDictionaryRW();
2211 :
2212 2 : if (nTextA != 255)
2213 : {
2214 2 : GDALPDFDictionaryRW* poGS1 = new GDALPDFDictionaryRW();
2215 4 : poGS1->Add("Type", GDALPDFObjectRW::CreateName("ExtGState"));
2216 2 : poGS1->Add("ca", (nTextA == 127 || nTextA == 128) ? 0.5 : nTextA / 255.0);
2217 :
2218 2 : GDALPDFDictionaryRW* poExtGState = new GDALPDFDictionaryRW();
2219 2 : poExtGState->Add("GS1", poGS1);
2220 :
2221 2 : poResources->Add("ExtGState", poExtGState);
2222 : }
2223 :
2224 2 : GDALPDFDictionaryRW* poDictFTimesRoman = NULL;
2225 2 : poDictFTimesRoman = new GDALPDFDictionaryRW();
2226 4 : poDictFTimesRoman->Add("Type", GDALPDFObjectRW::CreateName("Font"));
2227 2 : poDictFTimesRoman->Add("BaseFont", GDALPDFObjectRW::CreateName("Times-Roman"));
2228 2 : poDictFTimesRoman->Add("Encoding", GDALPDFObjectRW::CreateName("WinAnsiEncoding"));
2229 2 : poDictFTimesRoman->Add("Subtype", GDALPDFObjectRW::CreateName("Type1"));
2230 :
2231 2 : GDALPDFDictionaryRW* poDictFont = new GDALPDFDictionaryRW();
2232 2 : if (poDictFTimesRoman)
2233 2 : poDictFont->Add("FTimesRoman", poDictFTimesRoman);
2234 2 : poResources->Add("Font", poDictFont);
2235 :
2236 2 : oDict.Add("Resources", poResources);
2237 :
2238 2 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
2239 : }
2240 :
2241 : /* -------------------------------------------------------------- */
2242 : /* Write object stream */
2243 : /* -------------------------------------------------------------- */
2244 2 : VSIFPrintfL(fp, "stream\n");
2245 :
2246 2 : vsi_l_offset nStreamStart = VSIFTellL(fp);
2247 :
2248 2 : VSILFILE* fpGZip = NULL;
2249 2 : VSILFILE* fpBack = fp;
2250 2 : if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
2251 : {
2252 2 : fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
2253 2 : fp = fpGZip;
2254 : }
2255 :
2256 2 : double dfX = OGR_G_GetX(hGeom, 0) * adfMatrix[1] + adfMatrix[0];
2257 2 : double dfY = OGR_G_GetY(hGeom, 0) * adfMatrix[3] + adfMatrix[2];
2258 :
2259 2 : VSIFPrintfL(fp, "q\n");
2260 2 : VSIFPrintfL(fp, "BT\n");
2261 2 : if (nTextA != 255)
2262 : {
2263 2 : VSIFPrintfL(fp, "/GS1 gs\n");
2264 : }
2265 2 : if (dfTextAngle == 0)
2266 : {
2267 0 : VSIFPrintfL(fp, "%f %f Td\n", dfX, dfY);
2268 : }
2269 : else
2270 : {
2271 2 : dfTextAngle = - dfTextAngle * M_PI / 180.0;
2272 : VSIFPrintfL(fp, "%f %f %f %f %f %f Tm\n",
2273 : cos(dfTextAngle), -sin(dfTextAngle),
2274 : sin(dfTextAngle), cos(dfTextAngle),
2275 2 : dfX, dfY);
2276 : }
2277 2 : VSIFPrintfL(fp, "%f %f %f rg\n", nTextR / 255.0, nTextG / 255.0, nTextB / 255.0);
2278 2 : VSIFPrintfL(fp, "/FTimesRoman %f Tf\n", dfTextSize);
2279 2 : VSIFPrintfL(fp, "(");
2280 26 : for(size_t i=0;i<osLabelText.size();i++)
2281 : {
2282 : /*if (osLabelText[i] == '\n')
2283 : VSIFPrintfL(fp, ") Tj T* (");
2284 24 : else */if (osLabelText[i] >= 32 && osLabelText[i] <= 127)
2285 24 : VSIFPrintfL(fp, "%c", osLabelText[i]);
2286 : else
2287 0 : VSIFPrintfL(fp, "_");
2288 : }
2289 2 : VSIFPrintfL(fp, ") Tj\n");
2290 2 : VSIFPrintfL(fp, "ET\n");
2291 2 : VSIFPrintfL(fp, "Q");
2292 :
2293 2 : if (fpGZip)
2294 2 : VSIFCloseL(fpGZip);
2295 2 : fp = fpBack;
2296 :
2297 2 : vsi_l_offset nStreamEnd = VSIFTellL(fp);
2298 2 : VSIFPrintfL(fp, "\n");
2299 2 : VSIFPrintfL(fp, "endstream\n");
2300 2 : EndObj();
2301 :
2302 2 : StartObj(nObjectLengthId);
2303 : VSIFPrintfL(fp,
2304 : " %ld\n",
2305 2 : (long)(nStreamEnd - nStreamStart));
2306 2 : EndObj();
2307 : }
2308 : else
2309 : {
2310 12 : osVectorDesc.aIdsText.push_back(0);
2311 : }
2312 :
2313 : /* -------------------------------------------------------------- */
2314 : /* Write feature attributes */
2315 : /* -------------------------------------------------------------- */
2316 14 : int nFeatureUserProperties = 0;
2317 :
2318 14 : int iField = -1;
2319 14 : CPLString osFeatureName;
2320 :
2321 14 : if (bWriteOGRAttributes)
2322 : {
2323 14 : if (pszOGRDisplayField &&
2324 : (iField = OGR_FD_GetFieldIndex(OGR_F_GetDefnRef(hFeat), pszOGRDisplayField)) >= 0)
2325 6 : osFeatureName = OGR_F_GetFieldAsString(hFeat, iField);
2326 : else
2327 8 : osFeatureName = CPLSPrintf("feature%d", iObjLayer + 1);
2328 :
2329 14 : nFeatureUserProperties = AllocNewObject();
2330 14 : StartObj(nFeatureUserProperties);
2331 :
2332 14 : GDALPDFDictionaryRW oDict;
2333 14 : GDALPDFDictionaryRW* poDictA = new GDALPDFDictionaryRW();
2334 14 : oDict.Add("A", poDictA);
2335 14 : poDictA->Add("O", GDALPDFObjectRW::CreateName("UserProperties"));
2336 :
2337 14 : int nFields = OGR_F_GetFieldCount(hFeat);
2338 14 : GDALPDFArrayRW* poArray = new GDALPDFArrayRW();
2339 56 : for(int i = 0; i < nFields; i++)
2340 : {
2341 42 : if (OGR_F_IsFieldSet(hFeat, i))
2342 : {
2343 24 : OGRFieldDefnH hFDefn = OGR_F_GetFieldDefnRef( hFeat, i );
2344 24 : GDALPDFDictionaryRW* poKV = new GDALPDFDictionaryRW();
2345 48 : poKV->Add("N", OGR_Fld_GetNameRef(hFDefn));
2346 24 : if (OGR_Fld_GetType(hFDefn) == OFTInteger)
2347 8 : poKV->Add("V", OGR_F_GetFieldAsInteger(hFeat, i));
2348 16 : else if (OGR_Fld_GetType(hFDefn) == OFTReal)
2349 2 : poKV->Add("V", OGR_F_GetFieldAsDouble(hFeat, i));
2350 : else
2351 14 : poKV->Add("V", OGR_F_GetFieldAsString(hFeat, i));
2352 24 : poArray->Add(poKV);
2353 : }
2354 : }
2355 :
2356 14 : poDictA->Add("P", poArray);
2357 :
2358 14 : oDict.Add("K", iObj);
2359 14 : oDict.Add("P", osVectorDesc.nFeatureLayerId, 0);
2360 14 : oDict.Add("Pg", oPageContext.nPageId, 0);
2361 14 : oDict.Add("S", GDALPDFObjectRW::CreateName("feature"));
2362 14 : oDict.Add("T", osFeatureName);
2363 :
2364 14 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
2365 :
2366 14 : EndObj();
2367 : }
2368 :
2369 14 : iObj ++;
2370 14 : iObjLayer ++;
2371 :
2372 14 : osVectorDesc.aUserPropertiesIds.push_back(nFeatureUserProperties);
2373 14 : osVectorDesc.aFeatureNames.push_back(osFeatureName);
2374 :
2375 14 : return TRUE;
2376 : }
2377 :
2378 : #endif
2379 :
2380 : /************************************************************************/
2381 : /* EndPage() */
2382 : /************************************************************************/
2383 :
2384 92 : int GDALPDFWriter::EndPage(const char* pszExtraImages,
2385 : const char* pszExtraStream,
2386 : const char* pszExtraLayerName)
2387 : {
2388 92 : int nLayerExtraId = WriteOCG(pszExtraLayerName);
2389 :
2390 92 : int bHasTimesRoman = pszExtraStream && strstr(pszExtraStream, "/FTimesRoman");
2391 92 : int bHasTimesBold = pszExtraStream && strstr(pszExtraStream, "/FTimesBold");
2392 :
2393 : /* -------------------------------------------------------------- */
2394 : /* Write extra images */
2395 : /* -------------------------------------------------------------- */
2396 92 : std::vector<GDALPDFImageDesc> asExtraImageDesc;
2397 92 : if (pszExtraImages)
2398 : {
2399 2 : char** papszExtraImagesTokens = CSLTokenizeString2(pszExtraImages, ",", 0);
2400 2 : int nCount = CSLCount(papszExtraImagesTokens);
2401 2 : if ((nCount % 4) == 0)
2402 : {
2403 2 : double dfUserUnit = oPageContext.dfDPI / 72.0;
2404 4 : for(int i=0;i<nCount;i+=4)
2405 : {
2406 2 : const char* pszImageFilename = papszExtraImagesTokens[i+0];
2407 2 : double dfX = atof(papszExtraImagesTokens[i+1]);
2408 2 : double dfY = atof(papszExtraImagesTokens[i+2]);
2409 2 : double dfScale = atof(papszExtraImagesTokens[i+3]);
2410 2 : GDALDataset* poImageDS = (GDALDataset* )GDALOpen(pszImageFilename, GA_ReadOnly);
2411 2 : if (poImageDS)
2412 : {
2413 2 : int nColorTableId = WriteColorTable(poImageDS);
2414 : int nImageId = WriteBlock( poImageDS,
2415 : 0, 0,
2416 : poImageDS->GetRasterXSize(),
2417 : poImageDS->GetRasterYSize(),
2418 : nColorTableId,
2419 : COMPRESS_DEFAULT,
2420 : 0,
2421 : -1,
2422 : NULL,
2423 : NULL,
2424 2 : NULL );
2425 :
2426 2 : if (nImageId)
2427 : {
2428 : GDALPDFImageDesc oImageDesc;
2429 2 : oImageDesc.nImageId = nImageId;
2430 2 : oImageDesc.dfXSize = poImageDS->GetRasterXSize() / dfUserUnit * dfScale;
2431 2 : oImageDesc.dfYSize = poImageDS->GetRasterYSize() / dfUserUnit * dfScale;
2432 2 : oImageDesc.dfXOff = dfX;
2433 2 : oImageDesc.dfYOff = dfY - oImageDesc.dfYSize;
2434 :
2435 2 : asExtraImageDesc.push_back(oImageDesc);
2436 : }
2437 :
2438 2 : GDALClose(poImageDS);
2439 : }
2440 : }
2441 : }
2442 2 : CSLDestroy(papszExtraImagesTokens);
2443 : }
2444 :
2445 : /* -------------------------------------------------------------- */
2446 : /* Write content dictionary */
2447 : /* -------------------------------------------------------------- */
2448 92 : int nContentLengthId = AllocNewObject();
2449 :
2450 92 : StartObj(oPageContext.nContentId);
2451 : {
2452 92 : GDALPDFDictionaryRW oDict;
2453 92 : oDict.Add("Length", nContentLengthId, 0);
2454 92 : if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
2455 : {
2456 88 : oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
2457 : }
2458 92 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
2459 : }
2460 :
2461 : /* -------------------------------------------------------------- */
2462 : /* Write content stream */
2463 : /* -------------------------------------------------------------- */
2464 92 : VSIFPrintfL(fp, "stream\n");
2465 92 : vsi_l_offset nStreamStart = VSIFTellL(fp);
2466 :
2467 92 : VSILFILE* fpGZip = NULL;
2468 92 : VSILFILE* fpBack = fp;
2469 92 : if( oPageContext.eStreamCompressMethod != COMPRESS_NONE )
2470 : {
2471 88 : fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
2472 88 : fp = fpGZip;
2473 : }
2474 :
2475 : /* -------------------------------------------------------------- */
2476 : /* Write drawing instructions for raster blocks */
2477 : /* -------------------------------------------------------------- */
2478 92 : if (oPageContext.nOCGRasterId)
2479 2 : VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oPageContext.nOCGRasterId);
2480 :
2481 218 : for(size_t iImage = 0; iImage < oPageContext.asImageDesc.size(); iImage ++)
2482 : {
2483 126 : VSIFPrintfL(fp, "q\n");
2484 126 : GDALPDFObjectRW* poXSize = GDALPDFObjectRW::CreateReal(oPageContext.asImageDesc[iImage].dfXSize);
2485 126 : GDALPDFObjectRW* poYSize = GDALPDFObjectRW::CreateReal(oPageContext.asImageDesc[iImage].dfYSize);
2486 126 : GDALPDFObjectRW* poXOff = GDALPDFObjectRW::CreateReal(oPageContext.asImageDesc[iImage].dfXOff);
2487 126 : GDALPDFObjectRW* poYOff = GDALPDFObjectRW::CreateReal(oPageContext.asImageDesc[iImage].dfYOff);
2488 : VSIFPrintfL(fp, "%s 0 0 %s %s %s cm\n",
2489 : poXSize->Serialize().c_str(),
2490 : poYSize->Serialize().c_str(),
2491 : poXOff->Serialize().c_str(),
2492 126 : poYOff->Serialize().c_str());
2493 126 : delete poXSize;
2494 126 : delete poYSize;
2495 126 : delete poXOff;
2496 126 : delete poYOff;
2497 : VSIFPrintfL(fp, "/Image%d Do\n",
2498 126 : oPageContext.asImageDesc[iImage].nImageId);
2499 126 : VSIFPrintfL(fp, "Q\n");
2500 : }
2501 :
2502 92 : if (oPageContext.nOCGRasterId)
2503 2 : VSIFPrintfL(fp, "EMC\n");
2504 :
2505 : /* -------------------------------------------------------------- */
2506 : /* Write drawing instructions for vector features */
2507 : /* -------------------------------------------------------------- */
2508 92 : int iObj = 0;
2509 96 : for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
2510 : {
2511 4 : GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
2512 :
2513 4 : VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oLayerDesc.nOGCId);
2514 :
2515 18 : for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
2516 : {
2517 14 : CPLString osName = oLayerDesc.aFeatureNames[iVector];
2518 14 : if (osName.size())
2519 : {
2520 : VSIFPrintfL(fp, "/feature <</MCID %d>> BDC\n",
2521 14 : iObj);
2522 : }
2523 :
2524 14 : iObj ++;
2525 :
2526 14 : VSIFPrintfL(fp, "/Vector%d Do\n", oLayerDesc.aIds[iVector]);
2527 :
2528 14 : if (osName.size())
2529 : {
2530 14 : VSIFPrintfL(fp, "EMC\n");
2531 : }
2532 : }
2533 :
2534 4 : VSIFPrintfL(fp, "EMC\n");
2535 : }
2536 :
2537 : /* -------------------------------------------------------------- */
2538 : /* Write drawing instructions for labels of vector features */
2539 : /* -------------------------------------------------------------- */
2540 92 : iObj = 0;
2541 96 : for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
2542 : {
2543 4 : GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
2544 4 : if (oLayerDesc.nOCGTextId)
2545 : {
2546 2 : VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oLayerDesc.nOGCId);
2547 2 : VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", oLayerDesc.nOCGTextId);
2548 :
2549 8 : for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
2550 : {
2551 6 : if (oLayerDesc.aIdsText[iVector])
2552 : {
2553 2 : CPLString osName = oLayerDesc.aFeatureNames[iVector];
2554 2 : if (osName.size())
2555 : {
2556 : VSIFPrintfL(fp, "/feature <</MCID %d>> BDC\n",
2557 2 : iObj);
2558 : }
2559 :
2560 2 : VSIFPrintfL(fp, "/Text%d Do\n", oLayerDesc.aIdsText[iVector]);
2561 :
2562 2 : if (osName.size())
2563 : {
2564 2 : VSIFPrintfL(fp, "EMC\n");
2565 2 : }
2566 : }
2567 :
2568 6 : iObj ++;
2569 : }
2570 :
2571 2 : VSIFPrintfL(fp, "EMC\n");
2572 2 : VSIFPrintfL(fp, "EMC\n");
2573 : }
2574 : else
2575 2 : iObj += oLayerDesc.aIds.size();
2576 : }
2577 :
2578 : /* -------------------------------------------------------------- */
2579 : /* Write drawing instructions for extra content. */
2580 : /* -------------------------------------------------------------- */
2581 92 : if (pszExtraStream || asExtraImageDesc.size())
2582 : {
2583 2 : if (nLayerExtraId)
2584 2 : VSIFPrintfL(fp, "/OC /Lyr%d BDC\n", nLayerExtraId);
2585 :
2586 : /* -------------------------------------------------------------- */
2587 : /* Write drawing instructions for extra images. */
2588 : /* -------------------------------------------------------------- */
2589 4 : for(size_t iImage = 0; iImage < asExtraImageDesc.size(); iImage ++)
2590 : {
2591 2 : VSIFPrintfL(fp, "q\n");
2592 2 : GDALPDFObjectRW* poXSize = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfXSize);
2593 2 : GDALPDFObjectRW* poYSize = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfYSize);
2594 2 : GDALPDFObjectRW* poXOff = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfXOff);
2595 2 : GDALPDFObjectRW* poYOff = GDALPDFObjectRW::CreateReal(asExtraImageDesc[iImage].dfYOff);
2596 : VSIFPrintfL(fp, "%s 0 0 %s %s %s cm\n",
2597 : poXSize->Serialize().c_str(),
2598 : poYSize->Serialize().c_str(),
2599 : poXOff->Serialize().c_str(),
2600 2 : poYOff->Serialize().c_str());
2601 2 : delete poXSize;
2602 2 : delete poYSize;
2603 2 : delete poXOff;
2604 2 : delete poYOff;
2605 : VSIFPrintfL(fp, "/Image%d Do\n",
2606 2 : asExtraImageDesc[iImage].nImageId);
2607 2 : VSIFPrintfL(fp, "Q\n");
2608 : }
2609 :
2610 2 : if (pszExtraStream)
2611 2 : VSIFPrintfL(fp, "%s\n", pszExtraStream);
2612 :
2613 2 : if (nLayerExtraId)
2614 2 : VSIFPrintfL(fp, "EMC\n");
2615 : }
2616 :
2617 92 : if (fpGZip)
2618 88 : VSIFCloseL(fpGZip);
2619 92 : fp = fpBack;
2620 :
2621 92 : vsi_l_offset nStreamEnd = VSIFTellL(fp);
2622 92 : if (fpGZip)
2623 88 : VSIFPrintfL(fp, "\n");
2624 92 : VSIFPrintfL(fp, "endstream\n");
2625 92 : EndObj();
2626 :
2627 92 : StartObj(nContentLengthId);
2628 : VSIFPrintfL(fp,
2629 : " %ld\n",
2630 92 : (long)(nStreamEnd - nStreamStart));
2631 92 : EndObj();
2632 :
2633 : /* -------------------------------------------------------------- */
2634 : /* Write objects for feature tree. */
2635 : /* -------------------------------------------------------------- */
2636 92 : if (nStructTreeRootId)
2637 : {
2638 4 : int nParentTreeId = AllocNewObject();
2639 4 : StartObj(nParentTreeId);
2640 4 : VSIFPrintfL(fp, "<< /Nums [ 0 ");
2641 4 : VSIFPrintfL(fp, "[ ");
2642 8 : for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
2643 : {
2644 4 : GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
2645 18 : for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
2646 : {
2647 14 : int nId = oLayerDesc.aUserPropertiesIds[iVector];
2648 14 : if (nId)
2649 14 : VSIFPrintfL(fp, "%d 0 R ", nId);
2650 : }
2651 : }
2652 4 : VSIFPrintfL(fp, " ]\n");
2653 4 : VSIFPrintfL(fp, " ] >> \n");
2654 4 : EndObj();
2655 :
2656 4 : StartObj(nStructTreeRootId);
2657 : VSIFPrintfL(fp,
2658 : "<< "
2659 : "/Type /StructTreeRoot "
2660 : "/ParentTree %d 0 R "
2661 4 : "/K [ ", nParentTreeId);
2662 8 : for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
2663 : {
2664 4 : VSIFPrintfL(fp, "%d 0 R ", oPageContext.asVectorDesc[iLayer]. nFeatureLayerId);
2665 : }
2666 4 : VSIFPrintfL(fp,"] >>\n");
2667 4 : EndObj();
2668 : }
2669 :
2670 : /* -------------------------------------------------------------- */
2671 : /* Write page resource dictionary. */
2672 : /* -------------------------------------------------------------- */
2673 92 : StartObj(oPageContext.nResourcesId);
2674 : {
2675 92 : GDALPDFDictionaryRW oDict;
2676 92 : GDALPDFDictionaryRW* poDictXObject = new GDALPDFDictionaryRW();
2677 92 : oDict.Add("XObject", poDictXObject);
2678 : size_t iImage;
2679 218 : for(iImage = 0; iImage < oPageContext.asImageDesc.size(); iImage ++)
2680 : {
2681 : poDictXObject->Add(CPLSPrintf("Image%d", oPageContext.asImageDesc[iImage].nImageId),
2682 126 : oPageContext.asImageDesc[iImage].nImageId, 0);
2683 : }
2684 94 : for(iImage = 0; iImage < asExtraImageDesc.size(); iImage ++)
2685 : {
2686 : poDictXObject->Add(CPLSPrintf("Image%d", asExtraImageDesc[iImage].nImageId),
2687 2 : asExtraImageDesc[iImage].nImageId, 0);
2688 : }
2689 96 : for(size_t iLayer = 0; iLayer < oPageContext.asVectorDesc.size(); iLayer ++)
2690 : {
2691 4 : GDALPDFLayerDesc& oLayerDesc = oPageContext.asVectorDesc[iLayer];
2692 18 : for(size_t iVector = 0; iVector < oLayerDesc.aIds.size(); iVector ++)
2693 : {
2694 : poDictXObject->Add(CPLSPrintf("Vector%d", oLayerDesc.aIds[iVector]),
2695 14 : oLayerDesc.aIds[iVector], 0);
2696 14 : if (oLayerDesc.aIdsText[iVector])
2697 : poDictXObject->Add(CPLSPrintf("Text%d", oLayerDesc.aIdsText[iVector]),
2698 2 : oLayerDesc.aIdsText[iVector], 0);
2699 : }
2700 : }
2701 :
2702 92 : GDALPDFDictionaryRW* poDictFTimesRoman = NULL;
2703 92 : if (bHasTimesRoman)
2704 : {
2705 2 : poDictFTimesRoman = new GDALPDFDictionaryRW();
2706 4 : poDictFTimesRoman->Add("Type", GDALPDFObjectRW::CreateName("Font"));
2707 2 : poDictFTimesRoman->Add("BaseFont", GDALPDFObjectRW::CreateName("Times-Roman"));
2708 2 : poDictFTimesRoman->Add("Encoding", GDALPDFObjectRW::CreateName("WinAnsiEncoding"));
2709 2 : poDictFTimesRoman->Add("Subtype", GDALPDFObjectRW::CreateName("Type1"));
2710 : }
2711 :
2712 92 : GDALPDFDictionaryRW* poDictFTimesBold = NULL;
2713 92 : if (bHasTimesBold)
2714 : {
2715 0 : poDictFTimesBold = new GDALPDFDictionaryRW();
2716 0 : poDictFTimesBold->Add("Type", GDALPDFObjectRW::CreateName("Font"));
2717 0 : poDictFTimesBold->Add("BaseFont", GDALPDFObjectRW::CreateName("Times-Bold"));
2718 0 : poDictFTimesBold->Add("Encoding", GDALPDFObjectRW::CreateName("WinAnsiEncoding"));
2719 0 : poDictFTimesBold->Add("Subtype", GDALPDFObjectRW::CreateName("Type1"));
2720 : }
2721 :
2722 92 : if (poDictFTimesRoman != NULL || poDictFTimesBold != NULL)
2723 : {
2724 2 : GDALPDFDictionaryRW* poDictFont = new GDALPDFDictionaryRW();
2725 2 : if (poDictFTimesRoman)
2726 2 : poDictFont->Add("FTimesRoman", poDictFTimesRoman);
2727 2 : if (poDictFTimesBold)
2728 0 : poDictFont->Add("FTimesBold", poDictFTimesBold);
2729 2 : oDict.Add("Font", poDictFont);
2730 : }
2731 :
2732 92 : if (asOCGs.size())
2733 : {
2734 6 : GDALPDFDictionaryRW* poDictProperties = new GDALPDFDictionaryRW();
2735 16 : for(size_t i=0; i<asOCGs.size(); i++)
2736 : poDictProperties->Add(CPLSPrintf("Lyr%d", asOCGs[i].nId),
2737 10 : asOCGs[i].nId, 0);
2738 6 : oDict.Add("Properties", poDictProperties);
2739 : }
2740 :
2741 92 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
2742 : }
2743 92 : EndObj();
2744 :
2745 92 : return TRUE;
2746 : }
2747 :
2748 : /************************************************************************/
2749 : /* WriteMask() */
2750 : /************************************************************************/
2751 :
2752 6 : int GDALPDFWriter::WriteMask(GDALDataset* poSrcDS,
2753 : int nXOff, int nYOff, int nReqXSize, int nReqYSize,
2754 : PDFCompressMethod eCompressMethod)
2755 : {
2756 6 : int nMaskSize = nReqXSize * nReqYSize;
2757 6 : GByte* pabyMask = (GByte*)VSIMalloc(nMaskSize);
2758 6 : if (pabyMask == NULL)
2759 0 : return 0;
2760 :
2761 : CPLErr eErr;
2762 : eErr = poSrcDS->GetRasterBand(4)->RasterIO(
2763 : GF_Read,
2764 : nXOff, nYOff,
2765 : nReqXSize, nReqYSize,
2766 : pabyMask, nReqXSize, nReqYSize, GDT_Byte,
2767 6 : 0, 0);
2768 6 : if (eErr != CE_None)
2769 : {
2770 0 : VSIFree(pabyMask);
2771 0 : return 0;
2772 : }
2773 :
2774 6 : int bOnly0or255 = TRUE;
2775 6 : int bOnly255 = TRUE;
2776 6 : int bOnly0 = TRUE;
2777 : int i;
2778 6366 : for(i=0;i<nReqXSize * nReqYSize;i++)
2779 : {
2780 6364 : if (pabyMask[i] == 0)
2781 6360 : bOnly255 = FALSE;
2782 4 : else if (pabyMask[i] == 255)
2783 0 : bOnly0 = FALSE;
2784 : else
2785 : {
2786 4 : bOnly0or255 = FALSE;
2787 4 : break;
2788 : }
2789 : }
2790 :
2791 6 : if (bOnly255)
2792 : {
2793 0 : CPLFree(pabyMask);
2794 0 : return 0;
2795 : }
2796 :
2797 6 : if (bOnly0or255)
2798 : {
2799 : /* Translate to 1 bit */
2800 2 : int nReqXSize1 = (nReqXSize + 7) / 8;
2801 2 : GByte* pabyMask1 = (GByte*)VSICalloc(nReqXSize1, nReqYSize);
2802 2 : if (pabyMask1 == NULL)
2803 : {
2804 0 : CPLFree(pabyMask);
2805 0 : return 0;
2806 : }
2807 22 : for(int y=0;y<nReqYSize;y++)
2808 : {
2809 220 : for(int x=0;x<nReqXSize;x++)
2810 : {
2811 200 : if (pabyMask[y * nReqXSize + x])
2812 0 : pabyMask1[y * nReqXSize1 + x / 8] |= 1 << (7 - (x % 8));
2813 : }
2814 : }
2815 2 : VSIFree(pabyMask);
2816 2 : pabyMask = pabyMask1;
2817 2 : nMaskSize = nReqXSize1 * nReqYSize;
2818 : }
2819 :
2820 6 : int nMaskId = AllocNewObject();
2821 6 : int nMaskLengthId = AllocNewObject();
2822 :
2823 6 : StartObj(nMaskId);
2824 6 : GDALPDFDictionaryRW oDict;
2825 : oDict.Add("Length", nMaskLengthId, 0)
2826 6 : .Add("Type", GDALPDFObjectRW::CreateName("XObject"));
2827 6 : if( eCompressMethod != COMPRESS_NONE )
2828 : {
2829 6 : oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
2830 : }
2831 : oDict.Add("Subtype", GDALPDFObjectRW::CreateName("Image"))
2832 : .Add("Width", nReqXSize)
2833 : .Add("Height", nReqYSize)
2834 : .Add("ColorSpace", GDALPDFObjectRW::CreateName("DeviceGray"))
2835 6 : .Add("BitsPerComponent", (bOnly0or255) ? 1 : 8);
2836 6 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
2837 6 : VSIFPrintfL(fp, "stream\n");
2838 6 : vsi_l_offset nStreamStart = VSIFTellL(fp);
2839 :
2840 6 : VSILFILE* fpGZip = NULL;
2841 6 : VSILFILE* fpBack = fp;
2842 6 : if( eCompressMethod != COMPRESS_NONE )
2843 : {
2844 6 : fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
2845 6 : fp = fpGZip;
2846 : }
2847 :
2848 6 : VSIFWriteL(pabyMask, nMaskSize, 1, fp);
2849 6 : CPLFree(pabyMask);
2850 :
2851 6 : if (fpGZip)
2852 6 : VSIFCloseL(fpGZip);
2853 6 : fp = fpBack;
2854 :
2855 6 : vsi_l_offset nStreamEnd = VSIFTellL(fp);
2856 : VSIFPrintfL(fp,
2857 : "\n"
2858 6 : "endstream\n");
2859 6 : EndObj();
2860 :
2861 6 : StartObj(nMaskLengthId);
2862 : VSIFPrintfL(fp,
2863 : " %ld\n",
2864 6 : (long)(nStreamEnd - nStreamStart));
2865 6 : EndObj();
2866 :
2867 6 : return nMaskId;
2868 : }
2869 :
2870 : /************************************************************************/
2871 : /* WriteBlock() */
2872 : /************************************************************************/
2873 :
2874 128 : int GDALPDFWriter::WriteBlock(GDALDataset* poSrcDS,
2875 : int nXOff, int nYOff, int nReqXSize, int nReqYSize,
2876 : int nColorTableId,
2877 : PDFCompressMethod eCompressMethod,
2878 : int nPredictor,
2879 : int nJPEGQuality,
2880 : const char* pszJPEG2000_DRIVER,
2881 : GDALProgressFunc pfnProgress,
2882 : void * pProgressData)
2883 : {
2884 128 : int nBands = poSrcDS->GetRasterCount();
2885 :
2886 128 : CPLErr eErr = CE_None;
2887 128 : GDALDataset* poBlockSrcDS = NULL;
2888 128 : GDALDatasetH hMemDS = NULL;
2889 128 : GByte* pabyMEMDSBuffer = NULL;
2890 :
2891 128 : if (eCompressMethod == COMPRESS_DEFAULT)
2892 : {
2893 106 : GDALDataset* poSrcDSToTest = poSrcDS;
2894 :
2895 : /* Test if we can directly copy original JPEG content */
2896 : /* if available */
2897 212 : if (poSrcDS->GetDriver() != NULL &&
2898 106 : poSrcDS->GetDriver() == GDALGetDriverByName("VRT"))
2899 : {
2900 8 : VRTDataset* poVRTDS = (VRTDataset* )poSrcDS;
2901 8 : poSrcDSToTest = poVRTDS->GetSingleSimpleSource();
2902 : }
2903 :
2904 318 : if (poSrcDSToTest != NULL &&
2905 106 : poSrcDSToTest->GetDriver() != NULL &&
2906 106 : poSrcDSToTest->GetDriver() == GDALGetDriverByName("JPEG") &&
2907 : nXOff == 0 && nYOff == 0 &&
2908 : nReqXSize == poSrcDSToTest->GetRasterXSize() &&
2909 : nReqYSize == poSrcDSToTest->GetRasterYSize() &&
2910 : nJPEGQuality < 0)
2911 : {
2912 4 : VSILFILE* fpSrc = VSIFOpenL(poSrcDSToTest->GetDescription(), "rb");
2913 4 : if (fpSrc != NULL)
2914 : {
2915 4 : CPLDebug("PDF", "Copying directly original JPEG file");
2916 :
2917 4 : VSIFSeekL(fpSrc, 0, SEEK_END);
2918 4 : int nLength = (int)VSIFTellL(fpSrc);
2919 4 : VSIFSeekL(fpSrc, 0, SEEK_SET);
2920 :
2921 4 : int nImageId = AllocNewObject();
2922 :
2923 4 : StartObj(nImageId);
2924 :
2925 4 : GDALPDFDictionaryRW oDict;
2926 : oDict.Add("Length", nLength)
2927 : .Add("Type", GDALPDFObjectRW::CreateName("XObject"))
2928 : .Add("Filter", GDALPDFObjectRW::CreateName("DCTDecode"))
2929 : .Add("Subtype", GDALPDFObjectRW::CreateName("Image"))
2930 : .Add("Width", nReqXSize)
2931 : .Add("Height", nReqYSize)
2932 : .Add("ColorSpace",
2933 : (nBands == 1) ? GDALPDFObjectRW::CreateName("DeviceGray") :
2934 : GDALPDFObjectRW::CreateName("DeviceRGB"))
2935 4 : .Add("BitsPerComponent", 8);
2936 4 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
2937 4 : VSIFPrintfL(fp, "stream\n");
2938 :
2939 : GByte abyBuffer[1024];
2940 24 : for(int i=0;i<nLength;i += 1024)
2941 : {
2942 20 : int nRead = (int) VSIFReadL(abyBuffer, 1, 1024, fpSrc);
2943 20 : if ((int)VSIFWriteL(abyBuffer, 1, nRead, fp) != nRead)
2944 : {
2945 0 : eErr = CE_Failure;
2946 0 : break;
2947 : }
2948 :
2949 20 : if( eErr == CE_None && pfnProgress != NULL
2950 : && !pfnProgress( (i + nRead) / (double)nLength,
2951 : NULL, pProgressData ) )
2952 : {
2953 : CPLError( CE_Failure, CPLE_UserInterrupt,
2954 0 : "User terminated CreateCopy()" );
2955 0 : eErr = CE_Failure;
2956 0 : break;
2957 : }
2958 : }
2959 :
2960 4 : VSIFPrintfL(fp, "\nendstream\n");
2961 :
2962 4 : EndObj();
2963 :
2964 4 : VSIFCloseL(fpSrc);
2965 :
2966 4 : return eErr == CE_None ? nImageId : 0;
2967 : }
2968 : }
2969 :
2970 102 : eCompressMethod = COMPRESS_DEFLATE;
2971 : }
2972 :
2973 124 : int nMaskId = 0;
2974 124 : if (nBands == 4)
2975 : {
2976 : nMaskId = WriteMask(poSrcDS,
2977 : nXOff, nYOff, nReqXSize, nReqYSize,
2978 6 : eCompressMethod);
2979 : }
2980 :
2981 124 : if( nReqXSize == poSrcDS->GetRasterXSize() &&
2982 : nReqYSize == poSrcDS->GetRasterYSize() &&
2983 : nBands != 4)
2984 : {
2985 78 : poBlockSrcDS = poSrcDS;
2986 : }
2987 : else
2988 : {
2989 46 : if (nBands == 4)
2990 6 : nBands = 3;
2991 :
2992 46 : GDALDriverH hMemDriver = GDALGetDriverByName("MEM");
2993 46 : if( hMemDriver == NULL )
2994 0 : return 0;
2995 :
2996 : hMemDS = GDALCreate(hMemDriver, "MEM:::",
2997 : nReqXSize, nReqYSize, 0,
2998 46 : GDT_Byte, NULL);
2999 46 : if (hMemDS == NULL)
3000 0 : return 0;
3001 :
3002 : pabyMEMDSBuffer =
3003 46 : (GByte*)VSIMalloc3(nReqXSize, nReqYSize, nBands);
3004 46 : if (pabyMEMDSBuffer == NULL)
3005 : {
3006 0 : GDALClose(hMemDS);
3007 0 : return 0;
3008 : }
3009 :
3010 : eErr = poSrcDS->RasterIO(GF_Read,
3011 : nXOff, nYOff,
3012 : nReqXSize, nReqYSize,
3013 : pabyMEMDSBuffer, nReqXSize, nReqYSize,
3014 : GDT_Byte, nBands, NULL,
3015 46 : 0, 0, 0);
3016 :
3017 46 : if( eErr != CE_None )
3018 : {
3019 0 : CPLFree(pabyMEMDSBuffer);
3020 0 : GDALClose(hMemDS);
3021 0 : return 0;
3022 : }
3023 :
3024 : int iBand;
3025 104 : for(iBand = 0; iBand < nBands; iBand ++)
3026 : {
3027 58 : char** papszMEMDSOptions = NULL;
3028 : char szTmp[64];
3029 58 : memset(szTmp, 0, sizeof(szTmp));
3030 : CPLPrintPointer(szTmp,
3031 58 : pabyMEMDSBuffer + iBand * nReqXSize * nReqYSize, sizeof(szTmp));
3032 58 : papszMEMDSOptions = CSLSetNameValue(papszMEMDSOptions, "DATAPOINTER", szTmp);
3033 58 : GDALAddBand(hMemDS, GDT_Byte, papszMEMDSOptions);
3034 58 : CSLDestroy(papszMEMDSOptions);
3035 : }
3036 :
3037 46 : poBlockSrcDS = (GDALDataset*) hMemDS;
3038 : }
3039 :
3040 124 : int nImageId = AllocNewObject();
3041 124 : int nImageLengthId = AllocNewObject();
3042 :
3043 124 : StartObj(nImageId);
3044 :
3045 124 : GDALPDFDictionaryRW oDict;
3046 : oDict.Add("Length", nImageLengthId, 0)
3047 124 : .Add("Type", GDALPDFObjectRW::CreateName("XObject"));
3048 :
3049 124 : if( eCompressMethod == COMPRESS_DEFLATE )
3050 : {
3051 106 : oDict.Add("Filter", GDALPDFObjectRW::CreateName("FlateDecode"));
3052 106 : if( nPredictor == 2 )
3053 : oDict.Add("DecodeParms", &((new GDALPDFDictionaryRW())
3054 : ->Add("Predictor", 2)
3055 : .Add("Colors", nBands)
3056 4 : .Add("Columns", nReqXSize)));
3057 : }
3058 18 : else if( eCompressMethod == COMPRESS_JPEG )
3059 : {
3060 6 : oDict.Add("Filter", GDALPDFObjectRW::CreateName("DCTDecode"));
3061 : }
3062 12 : else if( eCompressMethod == COMPRESS_JPEG2000 )
3063 : {
3064 10 : oDict.Add("Filter", GDALPDFObjectRW::CreateName("JPXDecode"));
3065 : }
3066 :
3067 : oDict.Add("Subtype", GDALPDFObjectRW::CreateName("Image"))
3068 : .Add("Width", nReqXSize)
3069 : .Add("Height", nReqYSize)
3070 : .Add("ColorSpace",
3071 : (nColorTableId != 0) ? GDALPDFObjectRW::CreateIndirect(nColorTableId, 0) :
3072 : (nBands == 1) ? GDALPDFObjectRW::CreateName("DeviceGray") :
3073 : GDALPDFObjectRW::CreateName("DeviceRGB"))
3074 124 : .Add("BitsPerComponent", 8);
3075 124 : if( nMaskId )
3076 : {
3077 6 : oDict.Add("SMask", nMaskId, 0);
3078 : }
3079 124 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
3080 124 : VSIFPrintfL(fp, "stream\n");
3081 :
3082 124 : vsi_l_offset nStreamStart = VSIFTellL(fp);
3083 :
3084 140 : if( eCompressMethod == COMPRESS_JPEG ||
3085 : eCompressMethod == COMPRESS_JPEG2000 )
3086 : {
3087 16 : GDALDriver* poJPEGDriver = NULL;
3088 : char szTmp[64];
3089 16 : char** papszOptions = NULL;
3090 :
3091 16 : if( eCompressMethod == COMPRESS_JPEG )
3092 : {
3093 6 : poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JPEG");
3094 6 : if (poJPEGDriver != NULL && nJPEGQuality > 0)
3095 0 : papszOptions = CSLAddString(papszOptions, CPLSPrintf("QUALITY=%d", nJPEGQuality));
3096 6 : sprintf(szTmp, "/vsimem/pdftemp/%p.jpg", this);
3097 : }
3098 : else
3099 : {
3100 10 : if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JP2KAK"))
3101 2 : poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JP2KAK");
3102 10 : if (poJPEGDriver == NULL)
3103 : {
3104 10 : if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JP2ECW"))
3105 6 : poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JP2ECW");
3106 10 : if (poJPEGDriver)
3107 : {
3108 6 : papszOptions = CSLAddString(papszOptions, "PROFILE=NPJE");
3109 6 : papszOptions = CSLAddString(papszOptions, "LAYERS=1");
3110 6 : papszOptions = CSLAddString(papszOptions, "GeoJP2=OFF");
3111 6 : papszOptions = CSLAddString(papszOptions, "GMLJP2=OFF");
3112 : }
3113 : }
3114 10 : if (poJPEGDriver == NULL)
3115 : {
3116 4 : if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JP2OpenJPEG"))
3117 2 : poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JP2OpenJPEG");
3118 : }
3119 10 : if (poJPEGDriver == NULL)
3120 : {
3121 2 : if (pszJPEG2000_DRIVER == NULL || EQUAL(pszJPEG2000_DRIVER, "JPEG2000"))
3122 2 : poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JPEG2000");
3123 : }
3124 10 : sprintf(szTmp, "/vsimem/pdftemp/%p.jp2", this);
3125 : }
3126 :
3127 16 : if( poJPEGDriver == NULL )
3128 : {
3129 : CPLError(CE_Failure, CPLE_NotSupported,
3130 : "No %s driver found",
3131 0 : ( eCompressMethod == COMPRESS_JPEG ) ? "JPEG" : "JPEG2000");
3132 0 : eErr = CE_Failure;
3133 0 : goto end;
3134 : }
3135 :
3136 16 : GDALDataset* poJPEGDS = NULL;
3137 :
3138 : poJPEGDS = poJPEGDriver->CreateCopy(szTmp, poBlockSrcDS,
3139 : FALSE, papszOptions,
3140 16 : pfnProgress, pProgressData);
3141 :
3142 16 : CSLDestroy(papszOptions);
3143 16 : if( poJPEGDS == NULL )
3144 : {
3145 0 : eErr = CE_Failure;
3146 0 : goto end;
3147 : }
3148 :
3149 16 : GDALClose(poJPEGDS);
3150 :
3151 16 : vsi_l_offset nJPEGDataSize = 0;
3152 16 : GByte* pabyJPEGData = VSIGetMemFileBuffer(szTmp, &nJPEGDataSize, TRUE);
3153 16 : VSIFWriteL(pabyJPEGData, nJPEGDataSize, 1, fp);
3154 16 : CPLFree(pabyJPEGData);
3155 : }
3156 : else
3157 : {
3158 108 : VSILFILE* fpGZip = NULL;
3159 108 : VSILFILE* fpBack = fp;
3160 108 : if( eCompressMethod == COMPRESS_DEFLATE )
3161 : {
3162 106 : fpGZip = (VSILFILE* )VSICreateGZipWritable( (VSIVirtualHandle*) fp, TRUE, FALSE );
3163 106 : fp = fpGZip;
3164 : }
3165 :
3166 108 : GByte* pabyLine = (GByte*)CPLMalloc(nReqXSize * nBands);
3167 12838 : for(int iLine = 0; iLine < nReqYSize; iLine ++)
3168 : {
3169 : /* Get pixel interleaved data */
3170 : eErr = poBlockSrcDS->RasterIO(GF_Read,
3171 : 0, iLine, nReqXSize, 1,
3172 : pabyLine, nReqXSize, 1, GDT_Byte,
3173 12730 : nBands, NULL, nBands, 0, 1);
3174 12730 : if( eErr != CE_None )
3175 0 : break;
3176 :
3177 : /* Apply predictor if needed */
3178 12730 : if( nPredictor == 2 )
3179 : {
3180 1124 : if( nBands == 1 )
3181 : {
3182 1024 : int nPrevValue = pabyLine[0];
3183 524288 : for(int iPixel = 1; iPixel < nReqXSize; iPixel ++)
3184 : {
3185 523264 : int nCurValue = pabyLine[iPixel];
3186 523264 : pabyLine[iPixel] = (GByte) (nCurValue - nPrevValue);
3187 523264 : nPrevValue = nCurValue;
3188 : }
3189 : }
3190 100 : else if( nBands == 3 )
3191 : {
3192 100 : int nPrevValueR = pabyLine[0];
3193 100 : int nPrevValueG = pabyLine[1];
3194 100 : int nPrevValueB = pabyLine[2];
3195 5000 : for(int iPixel = 1; iPixel < nReqXSize; iPixel ++)
3196 : {
3197 4900 : int nCurValueR = pabyLine[3 * iPixel + 0];
3198 4900 : int nCurValueG = pabyLine[3 * iPixel + 1];
3199 4900 : int nCurValueB = pabyLine[3 * iPixel + 2];
3200 4900 : pabyLine[3 * iPixel + 0] = (GByte) (nCurValueR - nPrevValueR);
3201 4900 : pabyLine[3 * iPixel + 1] = (GByte) (nCurValueG - nPrevValueG);
3202 4900 : pabyLine[3 * iPixel + 2] = (GByte) (nCurValueB - nPrevValueB);
3203 4900 : nPrevValueR = nCurValueR;
3204 4900 : nPrevValueG = nCurValueG;
3205 4900 : nPrevValueB = nCurValueB;
3206 : }
3207 : }
3208 : }
3209 :
3210 12730 : if( VSIFWriteL(pabyLine, nReqXSize * nBands, 1, fp) != 1 )
3211 : {
3212 0 : eErr = CE_Failure;
3213 0 : break;
3214 : }
3215 :
3216 12730 : if( eErr == CE_None && pfnProgress != NULL
3217 : && !pfnProgress( (iLine+1) / (double)nReqYSize,
3218 : NULL, pProgressData ) )
3219 : {
3220 : CPLError( CE_Failure, CPLE_UserInterrupt,
3221 0 : "User terminated CreateCopy()" );
3222 0 : eErr = CE_Failure;
3223 0 : break;
3224 : }
3225 : }
3226 :
3227 108 : CPLFree(pabyLine);
3228 :
3229 108 : if (fpGZip)
3230 106 : VSIFCloseL(fpGZip);
3231 108 : fp = fpBack;
3232 : }
3233 :
3234 : end:
3235 124 : CPLFree(pabyMEMDSBuffer);
3236 124 : pabyMEMDSBuffer = NULL;
3237 124 : if( hMemDS != NULL )
3238 : {
3239 46 : GDALClose(hMemDS);
3240 46 : hMemDS = NULL;
3241 : }
3242 :
3243 124 : vsi_l_offset nStreamEnd = VSIFTellL(fp);
3244 : VSIFPrintfL(fp,
3245 : "\n"
3246 124 : "endstream\n");
3247 124 : EndObj();
3248 :
3249 124 : StartObj(nImageLengthId);
3250 : VSIFPrintfL(fp,
3251 : " %ld\n",
3252 124 : (long)(nStreamEnd - nStreamStart));
3253 124 : EndObj();
3254 :
3255 124 : return eErr == CE_None ? nImageId : 0;
3256 : }
3257 :
3258 : /************************************************************************/
3259 : /* WritePages() */
3260 : /************************************************************************/
3261 :
3262 92 : void GDALPDFWriter::WritePages()
3263 : {
3264 92 : StartObj(nPageResourceId);
3265 : {
3266 92 : GDALPDFDictionaryRW oDict;
3267 92 : GDALPDFArrayRW* poKids = new GDALPDFArrayRW();
3268 : oDict.Add("Type", GDALPDFObjectRW::CreateName("Pages"))
3269 : .Add("Count", (int)asPageId.size())
3270 184 : .Add("Kids", poKids);
3271 :
3272 184 : for(size_t i=0;i<asPageId.size();i++)
3273 92 : poKids->Add(asPageId[i], 0);
3274 :
3275 92 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
3276 : }
3277 92 : EndObj();
3278 :
3279 92 : StartObj(nCatalogId);
3280 : {
3281 92 : GDALPDFDictionaryRW oDict;
3282 : oDict.Add("Type", GDALPDFObjectRW::CreateName("Catalog"))
3283 184 : .Add("Pages", nPageResourceId, 0);
3284 92 : if (nXMPId)
3285 2 : oDict.Add("Metadata", nXMPId, 0);
3286 92 : if (asOCGs.size())
3287 : {
3288 6 : GDALPDFDictionaryRW* poDictOCProperties = new GDALPDFDictionaryRW();
3289 6 : oDict.Add("OCProperties", poDictOCProperties);
3290 :
3291 6 : GDALPDFDictionaryRW* poDictD = new GDALPDFDictionaryRW();
3292 6 : poDictOCProperties->Add("D", poDictD);
3293 :
3294 6 : GDALPDFArrayRW* poArrayOrder = new GDALPDFArrayRW();
3295 : size_t i;
3296 14 : for(i=0;i<asOCGs.size();i++)
3297 : {
3298 8 : poArrayOrder->Add(asOCGs[i].nId, 0);
3299 8 : if (i + 1 < asOCGs.size() && asOCGs[i+1].nParentId == asOCGs[i].nId)
3300 : {
3301 2 : GDALPDFArrayRW* poSubArrayOrder = new GDALPDFArrayRW();
3302 4 : poSubArrayOrder->Add(asOCGs[i+1].nId, 0);
3303 2 : poArrayOrder->Add(poSubArrayOrder);
3304 2 : i ++;
3305 : }
3306 : }
3307 6 : poDictD->Add("Order", poArrayOrder);
3308 :
3309 :
3310 6 : GDALPDFArrayRW* poArrayOGCs = new GDALPDFArrayRW();
3311 16 : for(i=0;i<asOCGs.size();i++)
3312 10 : poArrayOGCs->Add(asOCGs[i].nId, 0);
3313 6 : poDictOCProperties->Add("OCGs", poArrayOGCs);
3314 : }
3315 :
3316 92 : if (nStructTreeRootId)
3317 : {
3318 4 : GDALPDFDictionaryRW* poDictMarkInfo = new GDALPDFDictionaryRW();
3319 4 : oDict.Add("MarkInfo", poDictMarkInfo);
3320 4 : poDictMarkInfo->Add("UserProperties", GDALPDFObjectRW::CreateBool(TRUE));
3321 :
3322 4 : oDict.Add("StructTreeRoot", nStructTreeRootId, 0);
3323 : }
3324 :
3325 92 : VSIFPrintfL(fp, "%s\n", oDict.Serialize().c_str());
3326 : }
3327 92 : EndObj();
3328 92 : }
3329 :
3330 : /************************************************************************/
3331 : /* GDALPDFGetJPEGQuality() */
3332 : /************************************************************************/
3333 :
3334 94 : static int GDALPDFGetJPEGQuality(char** papszOptions)
3335 : {
3336 94 : int nJpegQuality = -1;
3337 94 : const char* pszValue = CSLFetchNameValue( papszOptions, "JPEG_QUALITY" );
3338 94 : if( pszValue != NULL )
3339 : {
3340 0 : nJpegQuality = atoi( pszValue );
3341 0 : if (!(nJpegQuality >= 1 && nJpegQuality <= 100))
3342 : {
3343 : CPLError( CE_Warning, CPLE_IllegalArg,
3344 : "JPEG_QUALITY=%s value not recognised, ignoring.",
3345 0 : pszValue );
3346 0 : nJpegQuality = -1;
3347 : }
3348 : }
3349 94 : return nJpegQuality;
3350 : }
3351 :
3352 : /************************************************************************/
3353 : /* GDALPDFCreateCopy() */
3354 : /************************************************************************/
3355 :
3356 120 : GDALDataset *GDALPDFCreateCopy( const char * pszFilename,
3357 : GDALDataset *poSrcDS,
3358 : int bStrict,
3359 : char **papszOptions,
3360 : GDALProgressFunc pfnProgress,
3361 : void * pProgressData )
3362 : {
3363 120 : int nBands = poSrcDS->GetRasterCount();
3364 120 : int nWidth = poSrcDS->GetRasterXSize();
3365 120 : int nHeight = poSrcDS->GetRasterYSize();
3366 :
3367 120 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
3368 0 : return NULL;
3369 :
3370 : /* -------------------------------------------------------------------- */
3371 : /* Some some rudimentary checks */
3372 : /* -------------------------------------------------------------------- */
3373 120 : if( nBands != 1 && nBands != 3 && nBands != 4 )
3374 : {
3375 : CPLError( CE_Failure, CPLE_NotSupported,
3376 : "PDF driver doesn't support %d bands. Must be 1 (grey or with color table), "
3377 6 : "3 (RGB) or 4 bands.\n", nBands );
3378 :
3379 6 : return NULL;
3380 : }
3381 :
3382 114 : GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
3383 114 : if( eDT != GDT_Byte )
3384 : {
3385 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3386 : "PDF driver doesn't support data type %s. "
3387 : "Only eight bit byte bands supported.\n",
3388 : GDALGetDataTypeName(
3389 20 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
3390 :
3391 20 : if (bStrict)
3392 20 : return NULL;
3393 : }
3394 :
3395 : /* -------------------------------------------------------------------- */
3396 : /* Read options. */
3397 : /* -------------------------------------------------------------------- */
3398 94 : PDFCompressMethod eCompressMethod = COMPRESS_DEFAULT;
3399 94 : const char* pszCompressMethod = CSLFetchNameValue(papszOptions, "COMPRESS");
3400 94 : if (pszCompressMethod)
3401 : {
3402 18 : if( EQUAL(pszCompressMethod, "NONE") )
3403 2 : eCompressMethod = COMPRESS_NONE;
3404 16 : else if( EQUAL(pszCompressMethod, "DEFLATE") )
3405 0 : eCompressMethod = COMPRESS_DEFLATE;
3406 16 : else if( EQUAL(pszCompressMethod, "JPEG") )
3407 6 : eCompressMethod = COMPRESS_JPEG;
3408 10 : else if( EQUAL(pszCompressMethod, "JPEG2000") )
3409 10 : eCompressMethod = COMPRESS_JPEG2000;
3410 : else
3411 : {
3412 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3413 0 : "Unsupported value for COMPRESS.");
3414 :
3415 0 : if (bStrict)
3416 0 : return NULL;
3417 : }
3418 : }
3419 :
3420 94 : PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
3421 94 : const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
3422 94 : if (pszStreamCompressMethod)
3423 : {
3424 4 : if( EQUAL(pszStreamCompressMethod, "NONE") )
3425 4 : eStreamCompressMethod = COMPRESS_NONE;
3426 0 : else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
3427 0 : eStreamCompressMethod = COMPRESS_DEFLATE;
3428 : else
3429 : {
3430 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3431 0 : "Unsupported value for STREAM_COMPRESS.");
3432 :
3433 0 : if (bStrict)
3434 0 : return NULL;
3435 : }
3436 : }
3437 :
3438 170 : if (nBands == 1 &&
3439 76 : poSrcDS->GetRasterBand(1)->GetColorTable() != NULL &&
3440 : (eCompressMethod == COMPRESS_JPEG || eCompressMethod == COMPRESS_JPEG2000))
3441 : {
3442 : CPLError( CE_Warning, CPLE_AppDefined,
3443 : "The source raster band has a color table, which is not appropriate with JPEG or JPEG2000 compression.\n"
3444 0 : "You should rather consider using color table expansion (-expand option in gdal_translate)");
3445 : }
3446 :
3447 :
3448 94 : int nBlockXSize = nWidth;
3449 94 : int nBlockYSize = nHeight;
3450 : const char* pszValue;
3451 :
3452 94 : int bTiled = CSLFetchBoolean( papszOptions, "TILED", FALSE );
3453 94 : if( bTiled )
3454 2 : nBlockXSize = nBlockYSize = 256;
3455 :
3456 94 : pszValue = CSLFetchNameValue(papszOptions, "BLOCKXSIZE");
3457 94 : if( pszValue != NULL )
3458 : {
3459 2 : nBlockXSize = atoi( pszValue );
3460 2 : if (nBlockXSize < 0 || nBlockXSize >= nWidth)
3461 0 : nBlockXSize = nWidth;
3462 : }
3463 :
3464 94 : pszValue = CSLFetchNameValue(papszOptions, "BLOCKYSIZE");
3465 94 : if( pszValue != NULL )
3466 : {
3467 2 : nBlockYSize = atoi( pszValue );
3468 2 : if (nBlockYSize < 0 || nBlockYSize >= nHeight)
3469 0 : nBlockYSize = nHeight;
3470 : }
3471 :
3472 94 : int nJPEGQuality = GDALPDFGetJPEGQuality(papszOptions);
3473 :
3474 94 : const char* pszJPEG2000_DRIVER = CSLFetchNameValue(papszOptions, "JPEG2000_DRIVER");
3475 :
3476 : const char* pszGEO_ENCODING =
3477 94 : CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
3478 :
3479 94 : const char* pszXMP = CSLFetchNameValue(papszOptions, "XMP");
3480 :
3481 94 : double dfDPI = atof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
3482 94 : if (dfDPI < 72.0)
3483 0 : dfDPI = 72.0;
3484 :
3485 94 : const char* pszPredictor = CSLFetchNameValue(papszOptions, "PREDICTOR");
3486 94 : int nPredictor = 1;
3487 94 : if (pszPredictor)
3488 : {
3489 4 : if (eCompressMethod == COMPRESS_DEFAULT)
3490 4 : eCompressMethod = COMPRESS_DEFLATE;
3491 :
3492 4 : if (eCompressMethod != COMPRESS_DEFLATE)
3493 : {
3494 : CPLError(CE_Warning, CPLE_NotSupported,
3495 0 : "PREDICTOR option is only taken into account for DEFLATE compression");
3496 : }
3497 : else
3498 : {
3499 4 : nPredictor = atoi(pszPredictor);
3500 4 : if (nPredictor != 1 && nPredictor != 2)
3501 : {
3502 : CPLError(CE_Warning, CPLE_NotSupported,
3503 0 : "Supported PREDICTOR values are 1 or 2");
3504 0 : nPredictor = 1;
3505 : }
3506 : }
3507 : }
3508 :
3509 94 : const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
3510 :
3511 94 : int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
3512 :
3513 : PDFMargins sMargins;
3514 94 : sMargins.nLeft = nMargin;
3515 94 : sMargins.nRight = nMargin;
3516 94 : sMargins.nTop = nMargin;
3517 94 : sMargins.nBottom = nMargin;
3518 :
3519 94 : const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
3520 94 : if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
3521 :
3522 94 : const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
3523 94 : if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
3524 :
3525 94 : const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
3526 94 : if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
3527 :
3528 94 : const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
3529 94 : if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
3530 :
3531 94 : const char* pszLayerName = CSLFetchNameValue(papszOptions, "LAYER_NAME");
3532 :
3533 94 : const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
3534 94 : const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
3535 94 : const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
3536 :
3537 94 : const char* pszOGRDataSource = CSLFetchNameValue(papszOptions, "OGR_DATASOURCE");
3538 94 : const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
3539 94 : const char* pszOGRDisplayLayerNames = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_LAYER_NAMES");
3540 94 : int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
3541 :
3542 : /* -------------------------------------------------------------------- */
3543 : /* Create file. */
3544 : /* -------------------------------------------------------------------- */
3545 94 : VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
3546 94 : if( fp == NULL )
3547 : {
3548 : CPLError( CE_Failure, CPLE_OpenFailed,
3549 : "Unable to create PDF file %s.\n",
3550 4 : pszFilename );
3551 4 : return NULL;
3552 : }
3553 :
3554 :
3555 90 : GDALPDFWriter oWriter(fp);
3556 :
3557 90 : if( CSLFetchBoolean(papszOptions, "WRITE_INFO", TRUE) )
3558 88 : oWriter.SetInfo(poSrcDS, papszOptions);
3559 90 : oWriter.SetXMP(poSrcDS, pszXMP);
3560 :
3561 : oWriter.StartPage(poSrcDS,
3562 : dfDPI,
3563 : pszGEO_ENCODING,
3564 : pszNEATLINE,
3565 : &sMargins,
3566 : eStreamCompressMethod,
3567 90 : pszOGRDataSource != NULL && bWriteOGRAttributes);
3568 :
3569 : int bRet = oWriter.WriteImagery(pszLayerName,
3570 : eCompressMethod,
3571 : nPredictor,
3572 : nJPEGQuality,
3573 : pszJPEG2000_DRIVER,
3574 : nBlockXSize, nBlockYSize,
3575 90 : pfnProgress, pProgressData);
3576 :
3577 : #ifdef OGR_ENABLED
3578 90 : if (bRet && pszOGRDataSource != NULL)
3579 : oWriter.WriteOGRDataSource(pszOGRDataSource,
3580 : pszOGRDisplayField,
3581 : pszOGRDisplayLayerNames,
3582 2 : bWriteOGRAttributes);
3583 : #endif
3584 :
3585 90 : if (bRet)
3586 : oWriter.EndPage(pszExtraImages,
3587 : pszExtraStream,
3588 90 : pszExtraLayerName);
3589 90 : oWriter.Close();
3590 :
3591 90 : if (!bRet)
3592 : {
3593 0 : VSIUnlink(pszFilename);
3594 0 : return NULL;
3595 : }
3596 : else
3597 : {
3598 : #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
3599 90 : return (GDALDataset*) GDALOpen(pszFilename, GA_ReadOnly);
3600 : #else
3601 : return new GDALFakePDFDataset();
3602 : #endif
3603 0 : }
3604 : }
|