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 4 : XPMDataset::XPMDataset()
63 :
64 : {
65 4 : }
66 :
67 : /************************************************************************/
68 : /* ~XPMDataset() */
69 : /************************************************************************/
70 :
71 4 : XPMDataset::~XPMDataset()
72 :
73 : {
74 4 : FlushCache();
75 4 : }
76 :
77 : /************************************************************************/
78 : /* Open() */
79 : /************************************************************************/
80 :
81 25782 : 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 25782 : if( poOpenInfo->nHeaderBytes < 32
91 : || strstr((const char *) poOpenInfo->pabyHeader,"XPM") == NULL
92 : || strstr((const char *) poOpenInfo->pabyHeader,"static") == NULL )
93 25778 : return NULL;
94 :
95 4 : 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 4 : VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
109 4 : if( fp == NULL )
110 0 : return NULL;
111 :
112 4 : VSIFSeekL( fp, 0, SEEK_END );
113 4 : nFileSize = (unsigned int) VSIFTellL( fp );
114 :
115 4 : pszFileContents = (char *) VSIMalloc(nFileSize+1);
116 4 : 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 4 : pszFileContents[nFileSize] = '\0';
125 :
126 4 : VSIFSeekL( fp, 0, SEEK_SET );
127 :
128 4 : 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 4 : VSIFCloseL(fp);
139 4 : fp = NULL;
140 :
141 : /* -------------------------------------------------------------------- */
142 : /* Convert into a binary image. */
143 : /* -------------------------------------------------------------------- */
144 : GByte *pabyImage;
145 : int nXSize, nYSize;
146 4 : GDALColorTable *poCT = NULL;
147 :
148 4 : CPLErrorReset();
149 :
150 4 : pabyImage = ParseXPM( pszFileContents, &nXSize, &nYSize, &poCT );
151 4 : CPLFree( pszFileContents );
152 :
153 4 : if( pabyImage == NULL )
154 : {
155 0 : return NULL;
156 : }
157 :
158 : /* -------------------------------------------------------------------- */
159 : /* Create a corresponding GDALDataset. */
160 : /* -------------------------------------------------------------------- */
161 : XPMDataset *poDS;
162 :
163 4 : poDS = new XPMDataset();
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Capture some information from the file that is of interest. */
167 : /* -------------------------------------------------------------------- */
168 4 : poDS->nRasterXSize = nXSize;
169 4 : 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 8 : TRUE );
178 4 : poBand->SetColorTable( poCT );
179 4 : poDS->SetBand( 1, poBand );
180 :
181 8 : delete poCT;
182 :
183 : /* -------------------------------------------------------------------- */
184 : /* Initialize any PAM information. */
185 : /* -------------------------------------------------------------------- */
186 4 : poDS->SetDescription( poOpenInfo->pszFilename );
187 4 : poDS->TryLoadXML();
188 :
189 : /* -------------------------------------------------------------------- */
190 : /* Support overviews. */
191 : /* -------------------------------------------------------------------- */
192 4 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
193 :
194 4 : return poDS;
195 : }
196 :
197 : /************************************************************************/
198 : /* XPMCreateCopy() */
199 : /************************************************************************/
200 :
201 : static GDALDataset *
202 36 : XPMCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
203 : int bStrict, char ** papszOptions,
204 : GDALProgressFunc pfnProgress, void * pProgressData )
205 :
206 : {
207 36 : int nBands = poSrcDS->GetRasterCount();
208 36 : int nXSize = poSrcDS->GetRasterXSize();
209 36 : int nYSize = poSrcDS->GetRasterYSize();
210 : GDALColorTable *poCT;
211 :
212 : /* -------------------------------------------------------------------- */
213 : /* Some some rudimentary checks */
214 : /* -------------------------------------------------------------------- */
215 36 : if( nBands != 1 )
216 : {
217 : CPLError( CE_Failure, CPLE_NotSupported,
218 10 : "XPM driver only supports one band images.\n" );
219 :
220 10 : return NULL;
221 : }
222 :
223 26 : 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 20 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
231 :
232 20 : 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 6 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
240 : int i;
241 6 : GDALColorTable oGreyTable;
242 :
243 6 : poCT = poBand->GetColorTable();
244 6 : if( poCT == NULL )
245 : {
246 6 : poCT = &oGreyTable;
247 :
248 1542 : for( i = 0; i < 256; i++ )
249 : {
250 : GDALColorEntry sColor;
251 :
252 1536 : sColor.c1 = (short) i;
253 1536 : sColor.c2 = (short) i;
254 1536 : sColor.c3 = (short) i;
255 1536 : sColor.c4 = 255;
256 :
257 1536 : 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 6 : const char *pszColorCodes = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-+=[]|:;,.<>?/";
266 :
267 : int anPixelMapping[256];
268 : GDALColorEntry asPixelColor[256];
269 6 : int nActiveColors = MIN(poCT->GetColorEntryCount(),256);
270 :
271 : // Setup initial colortable and pixel value mapping.
272 6 : memset( anPixelMapping+0, 0, sizeof(int) * 256 );
273 1542 : for( i = 0; i < nActiveColors; i++ )
274 : {
275 1536 : poCT->GetColorEntryAsRGB( i, asPixelColor + i );
276 1536 : anPixelMapping[i] = i;
277 : }
278 :
279 : /* ==================================================================== */
280 : /* Iterate merging colors until we are under our limit (about 85). */
281 : /* ==================================================================== */
282 1026 : while( nActiveColors > (int) strlen(pszColorCodes) )
283 : {
284 1014 : int nClosestDistance = 768;
285 1014 : int iClose1 = -1, iClose2 = -1;
286 : int iColor1, iColor2;
287 :
288 : // Find the closest pair of colors.
289 43350 : for( iColor1 = 0; iColor1 < nActiveColors; iColor1++ )
290 : {
291 5042880 : for( iColor2 = iColor1+1; iColor2 < nActiveColors; iColor2++ )
292 : {
293 : int nDistance;
294 :
295 4999530 : 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 4999530 : + ABS(asPixelColor[iColor1].c3-asPixelColor[iColor2].c3);
303 :
304 4999530 : if( nDistance < nClosestDistance )
305 : {
306 4194 : nClosestDistance = nDistance;
307 4194 : iClose1 = iColor1;
308 4194 : iClose2 = iColor2;
309 : }
310 : }
311 :
312 43350 : if( nClosestDistance < 8 )
313 1014 : break;
314 : }
315 :
316 : // This should never happen!
317 1014 : 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 260598 : for( i = 0; i < 256; i++ )
323 : {
324 259584 : if( anPixelMapping[i] == iClose2 )
325 1014 : anPixelMapping[i] = iClose1;
326 258570 : else if( anPixelMapping[i] == nActiveColors-1 )
327 678 : anPixelMapping[i] = iClose2;
328 : }
329 :
330 1014 : asPixelColor[iClose2] = asPixelColor[nActiveColors-1];
331 1014 : nActiveColors--;
332 : }
333 :
334 : /* ==================================================================== */
335 : /* Write the output image. */
336 : /* ==================================================================== */
337 : VSILFILE *fpPBM;
338 :
339 6 : fpPBM = VSIFOpenL( pszFilename, "wb+" );
340 6 : if( fpPBM == NULL )
341 : {
342 : CPLError( CE_Failure, CPLE_OpenFailed,
343 : "Unable to create file `%s'.",
344 4 : pszFilename );
345 :
346 4 : return NULL;
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Write the header lines. */
351 : /* -------------------------------------------------------------------- */
352 2 : VSIFPrintfL( fpPBM, "/* XPM */\n" );
353 : VSIFPrintfL( fpPBM, "static char *%s[] = {\n",
354 2 : CPLGetBasename( pszFilename ) );
355 2 : VSIFPrintfL( fpPBM, "/* width height num_colors chars_per_pixel */\n" );
356 : VSIFPrintfL( fpPBM, "\" %3d %3d %3d 1\",\n",
357 2 : nXSize, nYSize, nActiveColors );
358 2 : VSIFPrintfL( fpPBM, "/* colors */\n" );
359 :
360 : /* -------------------------------------------------------------------- */
361 : /* Write the color table. */
362 : /* -------------------------------------------------------------------- */
363 176 : for( i = 0; i < nActiveColors; i++ )
364 : {
365 174 : 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 174 : pszColorCodes[i],
371 : asPixelColor[i].c1,
372 : asPixelColor[i].c2,
373 348 : asPixelColor[i].c3 );
374 : }
375 :
376 : /* -------------------------------------------------------------------- */
377 : /* Dump image. */
378 : /* -------------------------------------------------------------------- */
379 : int iLine;
380 : GByte *pabyScanline;
381 :
382 2 : pabyScanline = (GByte *) CPLMalloc( nXSize );
383 22 : for( iLine = 0; iLine < nYSize; iLine++ )
384 : {
385 : poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
386 20 : (void *) pabyScanline, nXSize, 1, GDT_Byte, 0, 0 );
387 :
388 20 : VSIFPutcL( '"', fpPBM );
389 220 : for( int iPixel = 0; iPixel < nXSize; iPixel++ )
390 200 : VSIFPutcL( pszColorCodes[anPixelMapping[pabyScanline[iPixel]]],
391 200 : fpPBM);
392 20 : VSIFPrintfL( fpPBM, "\",\n" );
393 : }
394 :
395 2 : CPLFree( pabyScanline );
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* cleanup */
399 : /* -------------------------------------------------------------------- */
400 2 : VSIFPrintfL( fpPBM, "};\n" );
401 2 : VSIFCloseL( fpPBM );
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Re-open dataset, and copy any auxilary pam information. */
405 : /* -------------------------------------------------------------------- */
406 : GDALPamDataset *poDS = (GDALPamDataset *)
407 2 : GDALOpen( pszFilename, GA_ReadOnly );
408 :
409 2 : if( poDS )
410 2 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
411 :
412 2 : return poDS;
413 : }
414 :
415 : /************************************************************************/
416 : /* GDALRegister_XPM() */
417 : /************************************************************************/
418 :
419 1135 : void GDALRegister_XPM()
420 :
421 : {
422 : GDALDriver *poDriver;
423 :
424 1135 : if( GDALGetDriverByName( "XPM" ) == NULL )
425 : {
426 1093 : poDriver = new GDALDriver();
427 :
428 1093 : poDriver->SetDescription( "XPM" );
429 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
430 1093 : "X11 PixMap Format" );
431 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
432 1093 : "frmt_various.html#XPM" );
433 1093 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xpm" );
434 1093 : poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/x-xpixmap" );
435 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
436 1093 : "Byte" );
437 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
438 :
439 1093 : poDriver->pfnOpen = XPMDataset::Open;
440 1093 : poDriver->pfnCreateCopy = XPMCreateCopy;
441 :
442 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
443 : }
444 1135 : }
445 :
446 : /************************************************************************/
447 : /* ParseXPM() */
448 : /************************************************************************/
449 :
450 : static unsigned char *
451 4 : 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 4 : char **papszXPMList = NULL;
460 4 : const char *pszNext = pszInput;
461 : int i;
462 :
463 : // Skip till after open brace.
464 132 : while( *pszNext != '\0' && *pszNext != '{' )
465 124 : pszNext++;
466 :
467 4 : if( *pszNext == '\0' )
468 0 : return NULL;
469 :
470 4 : pszNext++;
471 :
472 : // Read lines till close brace.
473 :
474 4232 : while( *pszNext != '\0' && *pszNext != '}' )
475 : {
476 : // skip whole comment.
477 4224 : if( EQUALN(pszNext,"/*",2) )
478 : {
479 8 : pszNext += 2;
480 212 : while( *pszNext != '\0' && !EQUALN(pszNext,"*/",2) )
481 196 : pszNext++;
482 : }
483 :
484 : // reading string constants
485 4216 : else if( *pszNext == '"' )
486 : {
487 : char *pszLine;
488 :
489 1396 : pszNext++;
490 1396 : i = 0;
491 :
492 531240 : while( pszNext[i] != '\0' && pszNext[i] != '"' )
493 528448 : i++;
494 :
495 1396 : if( pszNext[i] == '\0' )
496 : {
497 0 : CSLDestroy( papszXPMList );
498 0 : return NULL;
499 : }
500 :
501 1396 : pszLine = (char *) CPLMalloc(i+1);
502 1396 : strncpy( pszLine, pszNext, i );
503 1396 : pszLine[i] = '\0';
504 :
505 1396 : papszXPMList = CSLAddString( papszXPMList, pszLine );
506 1396 : CPLFree( pszLine );
507 1396 : pszNext = pszNext + i + 1;
508 : }
509 :
510 : // just ignore everything else (whitespace, commas, newlines, etc).
511 : else
512 2820 : pszNext++;
513 : }
514 :
515 4 : 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 4 : 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 4 : 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 4 : GDALColorTable oCTable;
550 :
551 1028 : for( i = 0; i < 256; i++ )
552 1024 : anCharLookup[i] = -1;
553 :
554 352 : for( iColor = 0; iColor < nColorCount; iColor++ )
555 : {
556 348 : char **papszTokens = CSLTokenizeString( papszXPMList[iColor+1]+1 );
557 : GDALColorEntry sColor;
558 : int nRed, nGreen, nBlue;
559 :
560 348 : 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 348 : anCharLookup[(int)papszXPMList[iColor+1][0]] = iColor;
571 :
572 348 : 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 348 : 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 348 : sColor.c1 = (short) nRed;
592 348 : sColor.c2 = (short) nGreen;
593 348 : sColor.c3 = (short) nBlue;
594 348 : sColor.c4 = 255;
595 : }
596 :
597 348 : oCTable.SetColorEntry( iColor, &sColor );
598 :
599 348 : CSLDestroy( papszTokens );
600 : }
601 :
602 : /* -------------------------------------------------------------------- */
603 : /* Prepare image buffer. */
604 : /* -------------------------------------------------------------------- */
605 : GByte *pabyImage;
606 :
607 4 : pabyImage = (GByte *) VSIMalloc2(*pnXSize, *pnYSize);
608 4 : 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 4 : memset( pabyImage, 0, *pnXSize * *pnYSize );
618 :
619 : /* -------------------------------------------------------------------- */
620 : /* Parse image. */
621 : /* -------------------------------------------------------------------- */
622 1048 : for( int iLine = 0; iLine < *pnYSize; iLine++ )
623 : {
624 1044 : const char *pszInLine = papszXPMList[iLine + nColorCount + 1];
625 :
626 1044 : 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 1051064 : for( int iPixel = 0;
636 525532 : pszInLine[iPixel] != '\0' && iPixel < *pnXSize;
637 : iPixel++ )
638 : {
639 524488 : int nPixelValue = anCharLookup[(int)pszInLine[iPixel]];
640 524488 : if( nPixelValue != -1 )
641 524488 : pabyImage[iLine * *pnXSize + iPixel] = (GByte) nPixelValue;
642 : }
643 : }
644 :
645 4 : CSLDestroy( papszXPMList );
646 :
647 4 : *ppoRetTable = oCTable.Clone();
648 :
649 4 : return pabyImage;
650 : }
|