1 # include "bitmapConfig.h"
2
3 # include <stdio.h>
4 # include <stdlib.h>
5 # include <string.h>
6
7 # include <ctype.h>
8
9 # include <appDebugon.h>
10
11 # include "bmintern.h"
12
13 # if USE_LIBXPM
14
15 # include <X11/xpm.h>
16
17 /************************************************************************/
18 /* */
19 /* Translate an XPM color to BMcoRGB8PALETTE format; update mapping. */
20 /* */
21 /* 1) Translate transparent to white. */
22 /* */
23 /************************************************************************/
24
bmXpmPaletteColor(const char * c_color,int * pTransparent,RGB8Color * rgb8)25 static int bmXpmPaletteColor( const char * c_color,
26 int * pTransparent,
27 RGB8Color * rgb8 )
28 {
29 char ch;
30 unsigned r, g, b;
31
32 FILE * f;
33
34 /* 1 */
35 if ( ! c_color ||
36 ! strcmp( c_color, "None" ) ||
37 ! strcmp( c_color, "none" ) ||
38 ! strcmp( c_color, "Transparent" ) ||
39 ! strcmp( c_color, "transparent" ) )
40 {
41 *pTransparent= 1;
42 rgb8->rgb8Red= 255;
43 rgb8->rgb8Green= 255;
44 rgb8->rgb8Blue= 255;
45 rgb8->rgb8Alpha= 0;
46
47 return 0;
48 }
49
50 if ( sscanf( c_color, "#%4x%4x%4x%c", &r, &g, &b, &ch ) == 3 )
51 {
52 *pTransparent= 0;
53 rgb8->rgb8Red= r/ 256;
54 rgb8->rgb8Green= g/ 256;
55 rgb8->rgb8Blue= b/ 256;
56 rgb8->rgb8Alpha= 255;
57
58 return 0;
59 }
60
61 if ( sscanf( c_color, "#%2x%2x%2x%c", &r, &g, &b, &ch ) == 3 )
62 {
63 *pTransparent= 0;
64 rgb8->rgb8Red= r;
65 rgb8->rgb8Green= g;
66 rgb8->rgb8Blue= b;
67 rgb8->rgb8Alpha= 255;
68
69 return 0;
70 }
71
72 if ( sscanf( c_color, "#%1x%1x%1x%c", &r, &g, &b, &ch ) == 3 )
73 {
74 *pTransparent= 0;
75 rgb8->rgb8Red= r* 16;
76 rgb8->rgb8Green= g* 16;
77 rgb8->rgb8Blue= b* 16;
78 rgb8->rgb8Alpha= 255;
79
80 return 0;
81 }
82
83 f= fopen( "/usr/lib/X11/rgb.txt", "r" );
84 if ( f )
85 {
86 char line[100];
87 char color[100];
88
89 while( fgets( line, 100, f ) )
90 {
91 if ( sscanf( line, "%u %u %u %s", &r, &g, &b, color ) == 4 )
92 {
93 const char * s1= color;
94 const char * s2= c_color;
95
96 for (;;)
97 {
98 char c1;
99 char c2;
100
101 while( *s1 == ' ' ) { s1++; }
102 while( *s2 == ' ' ) { s2++; }
103
104 c1= *s1; c2= *s2;
105
106 if ( ! c1 && ! c2 )
107 {
108 *pTransparent= 0;
109 rgb8->rgb8Red= r;
110 rgb8->rgb8Green= g;
111 rgb8->rgb8Blue= b;
112 rgb8->rgb8Alpha= 255;
113
114 fclose( f ); return 0;
115 }
116
117 if ( isupper( c1 ) ) { c1= tolower( c1 ); }
118 if ( isupper( c2 ) ) { c2= tolower( c2 ); }
119
120 if ( c1 != c2 )
121 { break; }
122
123 s1++; s2++;
124 }
125 }
126 }
127
128 fclose( f );
129 }
130
131 SDEB(c_color); return -1;
132 }
133
134 /************************************************************************/
135 /* */
136 /* Read an XPM file. */
137 /* */
138 /************************************************************************/
139
bmReadXpmFile(const MemoryBuffer * filename,unsigned char ** pBuffer,BitmapDescription * bd,int * pPrivateFormat)140 int bmReadXpmFile( const MemoryBuffer * filename,
141 unsigned char ** pBuffer,
142 BitmapDescription * bd,
143 int * pPrivateFormat )
144 {
145 int rval= 0;
146
147 int ret;
148 unsigned int row;
149 unsigned int col;
150 unsigned char * buffer= (unsigned char *)0;
151
152 XpmImage image;
153
154 int bitsPerPixel= 8;
155
156 const char * fn= utilMemoryBufferGetString( filename );
157
158 memset( &image, 0, sizeof(image) );
159
160 ret= XpmReadFileToXpmImage( (char *)fn, &image, (XpmInfo *)0 );
161 if ( ret != XpmSuccess )
162 { SSDEB(fn,XpmGetErrorString(ret)); rval= -1; goto ready; }
163
164 if ( image.ncolors > 256* 256 )
165 { LDEB(image.ncolors); rval= -1; goto ready; }
166
167 bd->bdPixelsWide= image.width;
168 bd->bdPixelsHigh= image.height;
169
170 if ( image.ncolors > 256 && image.ncolors < 256* 256 )
171 { bitsPerPixel= 16; }
172
173 switch( bitsPerPixel )
174 {
175 case 8:
176 case 16:
177 bd->bdBitsPerSample= 8;
178 bd->bdSamplesPerPixel= 3;
179 bd->bdBitsPerPixel= bitsPerPixel;
180 bd->bdBytesPerRow= ( bd->bdBitsPerPixel+ 7 )/8* bd->bdPixelsWide;
181 bd->bdBufferLength= bd->bdPixelsHigh* bd->bdBytesPerRow;
182 bd->bdColorEncoding= BMcoRGB8PALETTE;
183 bd->bdHasAlpha= 0;
184 if ( utilPaletteSetCount( &(bd->bdPalette), image.ncolors ) )
185 { LDEB(image.ncolors); rval= -1; goto ready; }
186
187 for ( col= 0; col < image.ncolors; col++ )
188 {
189 int transparent= 0;
190
191 if ( bmXpmPaletteColor( image.colorTable[col].c_color,
192 &transparent, bd->bdPalette.cpColors+ col ) )
193 {
194 SSDEB(image.colorTable[col].string,
195 image.colorTable[col].c_color);
196 rval= -1; goto ready;
197 }
198
199 if ( transparent && ! bd->bdHasAlpha )
200 {
201 bd->bdHasAlpha= 1;
202 bd->bdBitsPerPixel= 2* bitsPerPixel;
203 }
204 }
205
206 if ( bmCalculateSizes( bd ) )
207 {
208 LDEB(bd->bdPalette.cpColorCount);
209 rval= -1; goto ready;
210 }
211
212 buffer= (unsigned char *)malloc( bd->bdBufferLength );
213 if ( ! buffer )
214 {
215 LXDEB(bd->bdBufferLength,buffer);
216 rval= -1; goto ready;
217 }
218 break;
219
220 default:
221 LDEB(bitsPerPixel);
222 LLDEB(image.cpp,image.ncolors);
223 rval= -1; goto ready;
224 }
225
226 bd->bdXResolution= bd->bdYResolution= 1;
227 bd->bdUnit= BMunPIXEL;
228
229 switch( bd->bdBitsPerPixel )
230 {
231 case 8:
232 if ( ! bd->bdHasAlpha )
233 {
234 unsigned int * from= image.data;
235
236 for ( row= 0; row < bd->bdPixelsHigh; row++ )
237 {
238 unsigned char * to= buffer+ row* bd->bdBytesPerRow;
239
240 for ( col= 0; col < bd->bdPixelsWide; to++, from++, col++ )
241 { *to= *from; }
242 }
243 }
244 else{
245 LDEB(bd->bdHasAlpha);
246 rval= -1; goto ready;
247 }
248
249 break;
250
251 case 16:
252 if ( ! bd->bdHasAlpha )
253 {
254 const unsigned int * from;
255 BmUint16 * to;
256
257 from= image.data;
258 to= (BmUint16 *)buffer;
259
260 for ( col= 0; col < bd->bdBufferLength; col++ )
261 { *(to++)= *(from++); }
262 }
263 else{
264 const unsigned int * from;
265 unsigned char * to;
266
267 from= image.data;
268 to= buffer;
269
270 for ( col= 0; col < bd->bdBufferLength; col += 2 )
271 {
272 int c= *(from++);
273
274 *(to++)= c;
275 *(to++)= bd->bdPalette.cpColors[c].rgb8Alpha;
276 }
277 }
278 break;
279
280 case 32:
281 if ( ! bd->bdHasAlpha )
282 { LDEB(bd->bdHasAlpha); rval= -1; goto ready; }
283 else{
284 const unsigned int * from;
285 unsigned char * to;
286 ColorPalette * cp= &(bd->bdPalette);
287
288 /* expand palette and alpha */
289 from= image.data;
290 to= buffer;
291
292 for ( col= 0; col < bd->bdBufferLength; col += 4 )
293 {
294 int c= *(from++);
295
296 *(to++)= cp->cpColors[c].rgb8Red;
297 *(to++)= cp->cpColors[c].rgb8Green;
298 *(to++)= cp->cpColors[c].rgb8Blue;
299 *(to++)= cp->cpColors[c].rgb8Alpha;
300 }
301
302 utilPaletteSetCount( cp, 0 );
303
304 bd->bdColorEncoding= BMcoRGB;
305 bd->bdHasAlpha= 1;
306 bd->bdBitsPerSample= 8;
307 bd->bdSamplesPerPixel= 4;
308 bd->bdBitsPerPixel= 32;
309 }
310 break;
311
312 default:
313 LLDEB(bd->bdBitsPerPixel,image.cpp); rval= -1; goto ready;
314 }
315
316 *pBuffer= buffer; buffer= (unsigned char *)0;
317 *pPrivateFormat= 0;
318
319 ready:
320
321 XpmFreeXpmImage( &image );
322
323 if ( buffer )
324 { free( buffer ); }
325
326 return rval;
327 }
328
329 /************************************************************************/
330 /* */
331 /* Write an XPM file. */
332 /* */
333 /************************************************************************/
334
bmXpmClean(XpmImage * xpmi)335 static void bmXpmClean( XpmImage * xpmi )
336 {
337 unsigned col;
338
339 if ( xpmi->data )
340 { free( xpmi->data ); }
341
342 for ( col= 0; col < xpmi->ncolors; col++ )
343 {
344 if ( xpmi->colorTable[col].string )
345 { free( xpmi->colorTable[col].string ); }
346 if ( xpmi->colorTable[col].symbolic )
347 { free( xpmi->colorTable[col].symbolic ); }
348 if ( xpmi->colorTable[col].m_color )
349 { free( xpmi->colorTable[col].m_color ); }
350 if ( xpmi->colorTable[col].g4_color )
351 { free( xpmi->colorTable[col].g4_color ); }
352 if ( xpmi->colorTable[col].g_color )
353 { free( xpmi->colorTable[col].g_color ); }
354 if ( xpmi->colorTable[col].c_color )
355 { free( xpmi->colorTable[col].c_color ); }
356 }
357
358 if ( xpmi->colorTable )
359 { free( xpmi->colorTable ); }
360
361 return;
362 }
363
bmXpmAllocColors(XpmImage * xpmi,int ncolors)364 static int bmXpmAllocColors( XpmImage * xpmi,
365 int ncolors )
366 {
367 int col;
368
369 xpmi->colorTable= (XpmColor *)malloc( xpmi->ncolors* sizeof(XpmColor) );
370 if ( ! xpmi->colorTable )
371 { LXDEB(ncolors,xpmi->colorTable); return -1; }
372
373 for ( col= 0; col < ncolors; col++ )
374 {
375 xpmi->colorTable[col].string= (char *)0;
376 xpmi->colorTable[col].symbolic= (char *)0;
377 xpmi->colorTable[col].m_color= (char *)0;
378 xpmi->colorTable[col].g4_color= (char *)0;
379 xpmi->colorTable[col].g_color= (char *)0;
380 xpmi->colorTable[col].c_color= (char *)0;
381 }
382
383 xpmi->ncolors= ncolors;
384
385 return 0;
386 }
387
bmXpmSetColor(XpmColor * xpmc,int charactersPerPixel,char * bytes,const RGB8Color * rgb8)388 static int bmXpmSetColor( XpmColor * xpmc,
389 int charactersPerPixel,
390 char * bytes,
391 const RGB8Color * rgb8 )
392 {
393 if ( rgb8->rgb8Alpha >= 128 )
394 {
395 xpmc->c_color= (char *)malloc( 14 );
396 if ( ! xpmc->c_color )
397 { XDEB(xpmc->c_color); return -1; }
398
399 sprintf( xpmc->c_color, "#%04x%04x%04x",
400 257* rgb8->rgb8Red,
401 257* rgb8->rgb8Green,
402 257* rgb8->rgb8Blue );
403 }
404 else{
405 xpmc->c_color= (char *)0;
406
407 /*strcpy( xpmc->xx_color, "None" );*/
408 }
409
410 xpmc->string= (char *)malloc( charactersPerPixel+ 1 );
411 if ( ! xpmc->string )
412 { XDEB(xpmc->string); return -1; }
413
414 memcpy( xpmc->string, bytes, charactersPerPixel );
415 xpmc->string[charactersPerPixel]= '\0';
416
417 return 0;
418 }
419
420 /************************************************************************/
421 /* */
422 /* Characters approximately in gray scale order. */
423 /* */
424 /************************************************************************/
425
426 static char BMXPMBytes[]=
427 " "
428 "."
429 "-,`'"
430 "_~:;"
431 "*^"
432 "!=+<>?1ijl|/"
433 "(){}"
434 "[]7"
435 "35"
436 "IJLT"
437 "CF"
438 "fcrst"
439 "Eea2SZ$G"
440 "69"
441 "K4AP"
442 "ovxyz"
443 "nuw"
444 "UYVXOkhQ"
445 "Bmg8D"
446 "bdpq"
447 "%&0N"
448 "@"
449 "RWHM"
450 "#"
451 ;
452
453 const int BMXPMBase= sizeof(BMXPMBytes)- 1;
454
455 /************************************************************************/
456 /* */
457 /* Build the palette of the raster image. */
458 /* */
459 /************************************************************************/
460
bmXpmFillPalette(XpmImage * image,const BitmapDescription * bd,const RGB8Color * palette)461 static int bmXpmFillPalette( XpmImage * image,
462 const BitmapDescription * bd,
463 const RGB8Color * palette )
464 {
465 int col;
466 int charactersPerPixel= 1;
467 int block= BMXPMBase;
468
469 while( block < image->ncolors )
470 {
471 charactersPerPixel++;
472 block *= BMXPMBase;
473 }
474
475 image->cpp= charactersPerPixel;
476
477 if ( bmXpmAllocColors( image, image->ncolors ) )
478 { LDEB(image->ncolors); return -1; }
479
480 for ( col= 0; col < image->ncolors; col++ )
481 {
482 int b;
483 int c= ( ( block- 1 )* col )/ ( image->ncolors-1 );
484 int idx= 0;
485 int blk= block/ BMXPMBase;
486 char scratch[20];
487
488 for ( b= 0; b < charactersPerPixel; b++ )
489 {
490 idx= c/ blk;
491
492 if ( idx < 0 || idx >= BMXPMBase )
493 { LLDEB(idx,BMXPMBase); return -1; }
494
495 scratch[b]= BMXPMBytes[idx];
496
497 c -= blk* idx;
498 blk /= BMXPMBase;
499 }
500
501 scratch[b]= '\0';
502
503 if ( bmXpmSetColor( image->colorTable+ col, charactersPerPixel,
504 scratch, palette+ col ) )
505 { XDEB(image->colorTable[col].c_color); return -1; }
506 }
507
508 return 0;
509 }
510
511 /************************************************************************/
512 /* */
513 /* Emot the raster image in XPM format. */
514 /* */
515 /************************************************************************/
516
bmWriteXpmFile(const MemoryBuffer * filename,const unsigned char * buffer,const BitmapDescription * bd,int privateFormat)517 int bmWriteXpmFile( const MemoryBuffer * filename,
518 const unsigned char * buffer,
519 const BitmapDescription * bd,
520 int privateFormat )
521 {
522 int rval= 0;
523
524 int row;
525 XpmImage image;
526
527 unsigned int * to;
528 int transparentColor= -1;
529
530 const char * fn= utilMemoryBufferGetString( filename );
531
532 const ColorPalette * cp= &(bd->bdPalette);
533
534 image.width= bd->bdPixelsWide;
535 image.height= bd->bdPixelsHigh;
536 image.cpp= 1;
537 image.ncolors= 0;
538 image.colorTable= (XpmColor *)0;
539 image.data= (unsigned int *)0;
540
541 switch( bd->bdColorEncoding )
542 {
543 RGB8Color BWPalette[257];
544 int colorCount;
545
546 case BMcoRGB8PALETTE:
547 image.ncolors= cp->cpColorCount;
548 if ( bmXpmFillPalette( &image, bd, cp->cpColors ) )
549 { LDEB(cp->cpColorCount); bmXpmClean( &image ); rval= -1; goto ready; }
550
551 break;
552
553 case BMcoBLACKWHITE:
554 case BMcoWHITEBLACK:
555 if ( bd->bdBitsPerSample > 8 )
556 { LDEB(bd->bdBitsPerSample); rval= -1; goto ready; }
557
558 if ( bmMakeGrayPalette( bd, &colorCount,
559 &transparentColor, BWPalette, 257 ) )
560 { LDEB(bd->bdBitsPerPixel); rval= -1; goto ready; }
561 image.ncolors= colorCount;
562
563 if ( bmXpmFillPalette( &image, bd, BWPalette ) )
564 { LDEB(colorCount); bmXpmClean( &image ); rval= -1; goto ready; }
565
566 break;
567
568 default:
569 LDEB(bd->bdColorEncoding); bmXpmClean( &image ); rval= -1; goto ready;
570 }
571
572 {
573 int size= ( image.width* image.height+ 7 )* sizeof( unsigned int );
574 image.data= (unsigned int *)malloc( size );
575 if ( ! image.data )
576 { LXDEB(size,image.data); rval= -1; goto ready; }
577 }
578
579 to= image.data;
580 for ( row= 0; row < bd->bdPixelsHigh; row++ )
581 {
582 const unsigned char * from= buffer+ row* bd->bdBytesPerRow;
583
584 if ( bmInflateToInt( to, from, bd, transparentColor, bd->bdHasAlpha ) )
585 { LDEB(bd->bdHasAlpha); rval= -1; goto ready; }
586
587 to += image.width;
588 }
589
590 {
591 int ret= XpmWriteFileFromXpmImage( (char *)fn, &image, (XpmInfo *)0 );
592 if ( ret != XpmSuccess )
593 { SSDEB(fn,XpmGetErrorString(ret)); rval= -1; goto ready; }
594 }
595
596 ready:
597
598 bmXpmClean( &image );
599
600 return rval;
601 }
602
bmCanWriteXpmFile(const BitmapDescription * bd,int privateFormat)603 int bmCanWriteXpmFile( const BitmapDescription * bd,
604 int privateFormat )
605 {
606 if ( bd->bdColorEncoding == BMcoBLACKWHITE ||
607 bd->bdColorEncoding == BMcoWHITEBLACK )
608 {
609 if ( bd->bdBitsPerSample <= 8 )
610 { return 0; }
611 }
612
613 if ( bd->bdColorEncoding != BMcoRGB8PALETTE )
614 { return -1; }
615
616 return 0;
617 }
618
619 # endif
620