1 : /******************************************************************************
2 : * $Id: xpmdataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $
3 : *
4 : * Project: XPM Driver
5 : * Purpose: Implement GDAL XPM Support
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_pam.h"
31 : #include "cpl_string.h"
32 : #include "memdataset.h"
33 : #include "gdal_frmts.h"
34 :
35 :
36 : CPL_CVSID("$Id: xpmdataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $");
37 :
38 : static unsigned char *ParseXPM( const char *pszInput,
39 : int *pnXSize, int *pnYSize,
40 : GDALColorTable **ppoRetTable );
41 :
42 :
43 : /************************************************************************/
44 : /* ==================================================================== */
45 : /* XPMDataset */
46 : /* ==================================================================== */
47 : /************************************************************************/
48 :
49 : class XPMDataset : public GDALPamDataset
50 : {
51 : public:
52 : XPMDataset();
53 : ~XPMDataset();
54 :
55 : static GDALDataset *Open( GDALOpenInfo * );
56 : };
57 :
58 : /************************************************************************/
59 : /* XPMDataset() */
60 : /************************************************************************/
61 :
62 2 : XPMDataset::XPMDataset()
63 :
64 : {
65 2 : }
66 :
67 : /************************************************************************/
68 : /* ~XPMDataset() */
69 : /************************************************************************/
70 :
71 2 : XPMDataset::~XPMDataset()
72 :
73 : {
74 2 : FlushCache();
75 2 : }
76 :
77 : /************************************************************************/
78 : /* Open() */
79 : /************************************************************************/
80 :
81 13657 : GDALDataset *XPMDataset::Open( GDALOpenInfo * poOpenInfo )
82 :
83 : {
84 : /* -------------------------------------------------------------------- */
85 : /* First we check to see if the file has the expected header */
86 : /* bytes. For now we expect the XPM file to start with a line */
87 : /* containing the letters XPM, and to have "static" in the */
88 : /* header. */
89 : /* -------------------------------------------------------------------- */
90 13657 : if( poOpenInfo->nHeaderBytes < 32
91 : || strstr((const char *) poOpenInfo->pabyHeader,"XPM") == NULL
92 : || strstr((const char *) poOpenInfo->pabyHeader,"static") == NULL )
93 13655 : return NULL;
94 :
95 2 : if( poOpenInfo->eAccess == GA_Update )
96 : {
97 : CPLError( CE_Failure, CPLE_NotSupported,
98 : "The XPM driver does not support update access to existing"
99 0 : " files." );
100 0 : return NULL;
101 : }
102 :
103 : /* -------------------------------------------------------------------- */
104 : /* Read the whole file into a memory strings. */
105 : /* -------------------------------------------------------------------- */
106 : unsigned int nFileSize;
107 : char *pszFileContents;
108 2 : VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
109 2 : if( fp == NULL )
110 0 : return NULL;
111 :
112 2 : VSIFSeekL( fp, 0, SEEK_END );
113 2 : nFileSize = (unsigned int) VSIFTellL( fp );
114 :
115 2 : pszFileContents = (char *) VSIMalloc(nFileSize+1);
116 2 : if( pszFileContents == NULL )
117 : {
118 : CPLError( CE_Failure, CPLE_OutOfMemory,
119 : "Insufficient memory for loading XPM file %s into memory.",
120 0 : poOpenInfo->pszFilename );
121 0 : VSIFCloseL(fp);
122 0 : return NULL;
123 : }
124 2 : pszFileContents[nFileSize] = '\0';
125 :
126 2 : VSIFSeekL( fp, 0, SEEK_SET );
127 :
128 2 : if( VSIFReadL( pszFileContents, 1, nFileSize, fp ) != nFileSize)
129 : {
130 0 : CPLFree( pszFileContents );
131 : CPLError( CE_Failure, CPLE_FileIO,
132 : "Failed to read all %d bytes from file %s.",
133 0 : nFileSize, poOpenInfo->pszFilename );
134 0 : VSIFCloseL(fp);
135 0 : return NULL;
136 : }
137 :
138 2 : VSIFCloseL(fp);
139 2 : fp = NULL;
140 :
141 : /* -------------------------------------------------------------------- */
142 : /* Convert into a binary image. */
143 : /* -------------------------------------------------------------------- */
144 : GByte *pabyImage;
145 : int nXSize, nYSize;
146 2 : GDALColorTable *poCT = NULL;
147 :
148 2 : CPLErrorReset();
149 :
150 2 : pabyImage = ParseXPM( pszFileContents, &nXSize, &nYSize, &poCT );
151 2 : CPLFree( pszFileContents );
152 :
153 2 : if( pabyImage == NULL )
154 : {
155 0 : return NULL;
156 : }
157 :
158 : /* -------------------------------------------------------------------- */
159 : /* Create a corresponding GDALDataset. */
160 : /* -------------------------------------------------------------------- */
161 : XPMDataset *poDS;
162 :
163 2 : poDS = new XPMDataset();
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Capture some information from the file that is of interest. */
167 : /* -------------------------------------------------------------------- */
168 2 : poDS->nRasterXSize = nXSize;
169 2 : poDS->nRasterYSize = nYSize;
170 :
171 : /* -------------------------------------------------------------------- */
172 : /* Create band information objects. */
173 : /* -------------------------------------------------------------------- */
174 : MEMRasterBand *poBand;
175 :
176 : poBand = new MEMRasterBand( poDS, 1, pabyImage, GDT_Byte, 1, nXSize,
177 4 : TRUE );
178 2 : poBand->SetColorTable( poCT );
179 2 : poDS->SetBand( 1, poBand );
180 :
181 4 : delete poCT;
182 :
183 : /* -------------------------------------------------------------------- */
184 : /* Initialize any PAM information. */
185 : /* -------------------------------------------------------------------- */
186 2 : poDS->SetDescription( poOpenInfo->pszFilename );
187 2 : poDS->TryLoadXML();
188 :
189 : /* -------------------------------------------------------------------- */
190 : /* Support overviews. */
191 : /* -------------------------------------------------------------------- */
192 2 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
193 :
194 2 : return poDS;
195 : }
196 :
197 : /************************************************************************/
198 : /* XPMCreateCopy() */
199 : /************************************************************************/
200 :
201 : static GDALDataset *
202 18 : XPMCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
203 : int bStrict, char ** papszOptions,
204 : GDALProgressFunc pfnProgress, void * pProgressData )
205 :
206 : {
207 18 : int nBands = poSrcDS->GetRasterCount();
208 18 : int nXSize = poSrcDS->GetRasterXSize();
209 18 : int nYSize = poSrcDS->GetRasterYSize();
210 : GDALColorTable *poCT;
211 :
212 : /* -------------------------------------------------------------------- */
213 : /* Some some rudimentary checks */
214 : /* -------------------------------------------------------------------- */
215 18 : if( nBands != 1 )
216 : {
217 : CPLError( CE_Failure, CPLE_NotSupported,
218 5 : "XPM driver only supports one band images.\n" );
219 :
220 5 : return NULL;
221 : }
222 :
223 13 : if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte
224 : && bStrict )
225 : {
226 : CPLError( CE_Failure, CPLE_NotSupported,
227 : "XPM driver doesn't support data type %s. "
228 : "Only eight bit bands supported.\n",
229 : GDALGetDataTypeName(
230 10 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
231 :
232 10 : return NULL;
233 : }
234 :
235 : /* -------------------------------------------------------------------- */
236 : /* If there is no colortable on the source image, create a */
237 : /* greyscale one with 64 levels of grey. */
238 : /* -------------------------------------------------------------------- */
239 3 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
240 : int i;
241 3 : GDALColorTable oGreyTable;
242 :
243 3 : poCT = poBand->GetColorTable();
244 3 : if( poCT == NULL )
245 : {
246 3 : poCT = &oGreyTable;
247 :
248 771 : for( i = 0; i < 256; i++ )
249 : {
250 : GDALColorEntry sColor;
251 :
252 768 : sColor.c1 = (short) i;
253 768 : sColor.c2 = (short) i;
254 768 : sColor.c3 = (short) i;
255 768 : sColor.c4 = 255;
256 :
257 768 : poCT->SetColorEntry( i, &sColor );
258 : }
259 : }
260 :
261 : /* -------------------------------------------------------------------- */
262 : /* Build list of active colors, and the mapping from pixels to */
263 : /* our active colormap. */
264 : /* -------------------------------------------------------------------- */
265 3 : const char *pszColorCodes = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-+=[]|:;,.<>?/";
266 :
267 : int anPixelMapping[256];
268 : GDALColorEntry asPixelColor[256];
269 3 : int nActiveColors = MIN(poCT->GetColorEntryCount(),256);
270 :
271 : // Setup initial colortable and pixel value mapping.
272 3 : memset( anPixelMapping+0, 0, sizeof(int) * 256 );
273 771 : for( i = 0; i < nActiveColors; i++ )
274 : {
275 768 : poCT->GetColorEntryAsRGB( i, asPixelColor + i );
276 768 : anPixelMapping[i] = i;
277 : }
278 :
279 : /* ==================================================================== */
280 : /* Iterate merging colors until we are under our limit (about 85). */
281 : /* ==================================================================== */
282 513 : while( nActiveColors > (int) strlen(pszColorCodes) )
283 : {
284 507 : int nClosestDistance = 768;
285 507 : int iClose1 = -1, iClose2 = -1;
286 : int iColor1, iColor2;
287 :
288 : // Find the closest pair of colors.
289 21675 : for( iColor1 = 0; iColor1 < nActiveColors; iColor1++ )
290 : {
291 2521440 : for( iColor2 = iColor1+1; iColor2 < nActiveColors; iColor2++ )
292 : {
293 : int nDistance;
294 :
295 2499765 : if( asPixelColor[iColor1].c4 < 128
296 : && asPixelColor[iColor2].c4 < 128 )
297 0 : nDistance = 0;
298 : else
299 : nDistance =
300 : ABS(asPixelColor[iColor1].c1-asPixelColor[iColor2].c1)
301 : + ABS(asPixelColor[iColor1].c2-asPixelColor[iColor2].c2)
302 2499765 : + ABS(asPixelColor[iColor1].c3-asPixelColor[iColor2].c3);
303 :
304 2499765 : if( nDistance < nClosestDistance )
305 : {
306 2097 : nClosestDistance = nDistance;
307 2097 : iClose1 = iColor1;
308 2097 : iClose2 = iColor2;
309 : }
310 : }
311 :
312 21675 : if( nClosestDistance < 8 )
313 507 : break;
314 : }
315 :
316 : // This should never happen!
317 507 : if( iClose1 == -1 )
318 0 : break;
319 :
320 : // Merge two selected colors - shift icolor2 into icolor1 and
321 : // move the last active color into icolor2's slot.
322 130299 : for( i = 0; i < 256; i++ )
323 : {
324 129792 : if( anPixelMapping[i] == iClose2 )
325 507 : anPixelMapping[i] = iClose1;
326 129285 : else if( anPixelMapping[i] == nActiveColors-1 )
327 339 : anPixelMapping[i] = iClose2;
328 : }
329 :
330 507 : asPixelColor[iClose2] = asPixelColor[nActiveColors-1];
331 507 : nActiveColors--;
332 : }
333 :
334 : /* ==================================================================== */
335 : /* Write the output image. */
336 : /* ==================================================================== */
337 : VSILFILE *fpPBM;
338 :
339 3 : fpPBM = VSIFOpenL( pszFilename, "wb+" );
340 3 : if( fpPBM == NULL )
341 : {
342 : CPLError( CE_Failure, CPLE_OpenFailed,
343 : "Unable to create file `%s'.",
344 2 : pszFilename );
345 :
346 2 : return NULL;
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Write the header lines. */
351 : /* -------------------------------------------------------------------- */
352 1 : VSIFPrintfL( fpPBM, "/* XPM */\n" );
353 : VSIFPrintfL( fpPBM, "static char *%s[] = {\n",
354 1 : CPLGetBasename( pszFilename ) );
355 1 : VSIFPrintfL( fpPBM, "/* width height num_colors chars_per_pixel */\n" );
356 : VSIFPrintfL( fpPBM, "\" %3d %3d %3d 1\",\n",
357 1 : nXSize, nYSize, nActiveColors );
358 1 : VSIFPrintfL( fpPBM, "/* colors */\n" );
359 :
360 : /* -------------------------------------------------------------------- */
361 : /* Write the color table. */
362 : /* -------------------------------------------------------------------- */
363 88 : for( i = 0; i < nActiveColors; i++ )
364 : {
365 87 : if( asPixelColor[i].c4 < 128 )
366 0 : VSIFPrintfL( fpPBM, "\"%c c None\",\n", pszColorCodes[i] );
367 : else
368 : VSIFPrintfL( fpPBM,
369 : "\"%c c #%02x%02x%02x\",\n",
370 87 : pszColorCodes[i],
371 : asPixelColor[i].c1,
372 : asPixelColor[i].c2,
373 174 : asPixelColor[i].c3 );
374 : }
375 :
376 : /* -------------------------------------------------------------------- */
377 : /* Dump image. */
378 : /* -------------------------------------------------------------------- */
379 : int iLine;
380 : GByte *pabyScanline;
381 :
382 1 : pabyScanline = (GByte *) CPLMalloc( nXSize );
383 11 : for( iLine = 0; iLine < nYSize; iLine++ )
384 : {
385 : poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
386 10 : (void *) pabyScanline, nXSize, 1, GDT_Byte, 0, 0 );
387 :
388 10 : VSIFPutcL( '"', fpPBM );
389 110 : for( int iPixel = 0; iPixel < nXSize; iPixel++ )
390 100 : VSIFPutcL( pszColorCodes[anPixelMapping[pabyScanline[iPixel]]],
391 100 : fpPBM);
392 10 : VSIFPrintfL( fpPBM, "\",\n" );
393 : }
394 :
395 1 : CPLFree( pabyScanline );
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* cleanup */
399 : /* -------------------------------------------------------------------- */
400 1 : VSIFPrintfL( fpPBM, "};\n" );
401 1 : VSIFCloseL( fpPBM );
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Re-open dataset, and copy any auxilary pam information. */
405 : /* -------------------------------------------------------------------- */
406 : GDALPamDataset *poDS = (GDALPamDataset *)
407 1 : GDALOpen( pszFilename, GA_ReadOnly );
408 :
409 1 : if( poDS )
410 1 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
411 :
412 1 : return poDS;
413 : }
414 :
415 : /************************************************************************/
416 : /* GDALRegister_XPM() */
417 : /************************************************************************/
418 :
419 582 : void GDALRegister_XPM()
420 :
421 : {
422 : GDALDriver *poDriver;
423 :
424 582 : if( GDALGetDriverByName( "XPM" ) == NULL )
425 : {
426 561 : poDriver = new GDALDriver();
427 :
428 561 : poDriver->SetDescription( "XPM" );
429 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
430 561 : "X11 PixMap Format" );
431 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
432 561 : "frmt_various.html#XPM" );
433 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xpm" );
434 561 : poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/x-xpixmap" );
435 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
436 561 : "Byte" );
437 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
438 :
439 561 : poDriver->pfnOpen = XPMDataset::Open;
440 561 : poDriver->pfnCreateCopy = XPMCreateCopy;
441 :
442 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
443 : }
444 582 : }
445 :
446 : /************************************************************************/
447 : /* ParseXPM() */
448 : /************************************************************************/
449 :
450 : static unsigned char *
451 2 : ParseXPM( const char *pszInput, int *pnXSize, int *pnYSize,
452 : GDALColorTable **ppoRetTable )
453 :
454 : {
455 : /* ==================================================================== */
456 : /* Parse input into an array of strings from within the first C */
457 : /* initializer (list os comma separated strings in braces). */
458 : /* ==================================================================== */
459 2 : char **papszXPMList = NULL;
460 2 : const char *pszNext = pszInput;
461 : int i;
462 :
463 : // Skip till after open brace.
464 66 : while( *pszNext != '\0' && *pszNext != '{' )
465 62 : pszNext++;
466 :
467 2 : if( *pszNext == '\0' )
468 0 : return NULL;
469 :
470 2 : pszNext++;
471 :
472 : // Read lines till close brace.
473 :
474 2116 : while( *pszNext != '\0' && *pszNext != '}' )
475 : {
476 : // skip whole comment.
477 2112 : if( EQUALN(pszNext,"/*",2) )
478 : {
479 4 : pszNext += 2;
480 106 : while( *pszNext != '\0' && !EQUALN(pszNext,"*/",2) )
481 98 : pszNext++;
482 : }
483 :
484 : // reading string constants
485 2108 : else if( *pszNext == '"' )
486 : {
487 : char *pszLine;
488 :
489 698 : pszNext++;
490 698 : i = 0;
491 :
492 265620 : while( pszNext[i] != '\0' && pszNext[i] != '"' )
493 264224 : i++;
494 :
495 698 : if( pszNext[i] == '\0' )
496 : {
497 0 : CSLDestroy( papszXPMList );
498 0 : return NULL;
499 : }
500 :
501 698 : pszLine = (char *) CPLMalloc(i+1);
502 698 : strncpy( pszLine, pszNext, i );
503 698 : pszLine[i] = '\0';
504 :
505 698 : papszXPMList = CSLAddString( papszXPMList, pszLine );
506 698 : CPLFree( pszLine );
507 698 : pszNext = pszNext + i + 1;
508 : }
509 :
510 : // just ignore everything else (whitespace, commas, newlines, etc).
511 : else
512 1410 : pszNext++;
513 : }
514 :
515 2 : if( CSLCount(papszXPMList) < 3 || *pszNext != '}' )
516 : {
517 0 : CSLDestroy( papszXPMList );
518 0 : return NULL;
519 : }
520 :
521 : /* -------------------------------------------------------------------- */
522 : /* Get the image information. */
523 : /* -------------------------------------------------------------------- */
524 : int nColorCount, nCharsPerPixel;
525 :
526 2 : if( sscanf( papszXPMList[0], "%d %d %d %d",
527 : pnXSize, pnYSize, &nColorCount, &nCharsPerPixel ) != 4 )
528 : {
529 : CPLError( CE_Failure, CPLE_AppDefined,
530 : "Image definition (%s) not well formed.",
531 0 : papszXPMList[0] );
532 0 : CSLDestroy( papszXPMList );
533 0 : return NULL;
534 : }
535 :
536 2 : if( nCharsPerPixel != 1 )
537 : {
538 : CPLError( CE_Failure, CPLE_AppDefined,
539 0 : "Only one character per pixel XPM images supported by GDAL at this time." );
540 0 : CSLDestroy( papszXPMList );
541 0 : return NULL;
542 : }
543 :
544 : /* -------------------------------------------------------------------- */
545 : /* Parse out colors. */
546 : /* -------------------------------------------------------------------- */
547 : int iColor;
548 : int anCharLookup[256];
549 2 : GDALColorTable oCTable;
550 :
551 514 : for( i = 0; i < 256; i++ )
552 512 : anCharLookup[i] = -1;
553 :
554 176 : for( iColor = 0; iColor < nColorCount; iColor++ )
555 : {
556 174 : char **papszTokens = CSLTokenizeString( papszXPMList[iColor+1]+1 );
557 : GDALColorEntry sColor;
558 : int nRed, nGreen, nBlue;
559 :
560 174 : if( CSLCount(papszTokens) != 2 || !EQUAL(papszTokens[0],"c") )
561 : {
562 : CPLError( CE_Failure, CPLE_AppDefined,
563 : "Ill formed color definition (%s) in XPM header.",
564 0 : papszXPMList[iColor+1] );
565 0 : CSLDestroy( papszXPMList );
566 0 : CSLDestroy( papszTokens );
567 0 : return NULL;
568 : }
569 :
570 174 : anCharLookup[(int)papszXPMList[iColor+1][0]] = iColor;
571 :
572 174 : if( EQUAL(papszTokens[1],"None") )
573 : {
574 0 : sColor.c1 = 0;
575 0 : sColor.c2 = 0;
576 0 : sColor.c3 = 0;
577 0 : sColor.c4 = 0;
578 : }
579 174 : else if( sscanf( papszTokens[1], "#%02x%02x%02x",
580 : &nRed, &nGreen, &nBlue ) != 3 )
581 : {
582 : CPLError( CE_Failure, CPLE_AppDefined,
583 : "Ill formed color definition (%s) in XPM header.",
584 0 : papszXPMList[iColor+1] );
585 0 : CSLDestroy( papszXPMList );
586 0 : CSLDestroy( papszTokens );
587 0 : return NULL;
588 : }
589 : else
590 : {
591 174 : sColor.c1 = (short) nRed;
592 174 : sColor.c2 = (short) nGreen;
593 174 : sColor.c3 = (short) nBlue;
594 174 : sColor.c4 = 255;
595 : }
596 :
597 174 : oCTable.SetColorEntry( iColor, &sColor );
598 :
599 174 : CSLDestroy( papszTokens );
600 : }
601 :
602 : /* -------------------------------------------------------------------- */
603 : /* Prepare image buffer. */
604 : /* -------------------------------------------------------------------- */
605 : GByte *pabyImage;
606 :
607 2 : pabyImage = (GByte *) VSIMalloc2(*pnXSize, *pnYSize);
608 2 : if( pabyImage == NULL )
609 : {
610 : CPLError( CE_Failure, CPLE_OutOfMemory,
611 : "Insufficient memory for %dx%d XPM image buffer.",
612 0 : *pnXSize, *pnYSize );
613 0 : CSLDestroy( papszXPMList );
614 0 : return NULL;
615 : }
616 :
617 2 : memset( pabyImage, 0, *pnXSize * *pnYSize );
618 :
619 : /* -------------------------------------------------------------------- */
620 : /* Parse image. */
621 : /* -------------------------------------------------------------------- */
622 524 : for( int iLine = 0; iLine < *pnYSize; iLine++ )
623 : {
624 522 : const char *pszInLine = papszXPMList[iLine + nColorCount + 1];
625 :
626 522 : if( pszInLine == NULL )
627 : {
628 0 : CPLFree( pabyImage );
629 0 : CSLDestroy( papszXPMList );
630 : CPLError( CE_Failure, CPLE_AppDefined,
631 0 : "Insufficient imagery lines in XPM image." );
632 0 : return NULL;
633 : }
634 :
635 525532 : for( int iPixel = 0;
636 262766 : pszInLine[iPixel] != '\0' && iPixel < *pnXSize;
637 : iPixel++ )
638 : {
639 262244 : int nPixelValue = anCharLookup[(int)pszInLine[iPixel]];
640 262244 : if( nPixelValue != -1 )
641 262244 : pabyImage[iLine * *pnXSize + iPixel] = (GByte) nPixelValue;
642 : }
643 : }
644 :
645 2 : CSLDestroy( papszXPMList );
646 :
647 2 : *ppoRetTable = oCTable.Clone();
648 :
649 2 : return pabyImage;
650 : }
|