1/* STARTHEADER 2 * 3 * File : sgi.c 4 * 5 * Author : Paul Obermeier (paul@poSoft.de) 6 * 7 * Date : Wed Nov 22 21:45:17 CET 2000 8 * 9 * Copyright : (C) 2000-2002 Paul Obermeier 10 * 11 * Description : 12 * 13 * A photo image handler for Silicon Graphics' native file format. 14 * 15 * The following image types are supported: 16 * 17 * 24-bit pixels: True-color (RGB, each channel 8 bit). 18 * 32-bit pixels: True-color with alpha channel (RGBA, each channel 8 bit). 19 * 48-bit pixels: True-color (RGB, each channel 16 bit). 20 * 64-bit pixels: True-color with alpha channel (RGBA, each channel 16 bit). 21 * 22 * List of currently supported features: 23 * 24 * Type | Read | Write | 25 * | -file | -data | -file | -data | 26 * ---------------------------------------- 27 * 24-bit | Yes | Yes* | Yes | Yes* | 28 * 32-bit | Yes | Yes* | Yes | Yes* | 29 * 48-bit | Yes | Yes* | No | No | 30 * 64-bit | Yes | Yes* | No | No | 31 * 32 * *: Implemented by reading/writing from/to a temporary file. This will 33 * be slow for larger images. 34 * 35 * All images types may be either uncompressed or run-length encoded. 36 * 37 * 38 * The following format options are available: 39 * 40 * Read SGI image: "sgi -matte <bool> -verbose <bool>" 41 * Write SGI image: "sgi -matte <bool> -verbose <bool> -compression <type>" 42 * 43 * -matte <bool>: If set to false, a matte (alpha) channel is ignored 44 * during reading or writing. Default is true. 45 * -verbose <bool>: If set to true, additional information about the file 46 * format is printed to stdout. Default is false. 47 * -compression <type>: Set the compression mode to either "none" or "rle". 48 * Default is "rle". 49 * 50 * Notes: 51 * 52 * - Parts of this code are taken from Paul Haeberli's original 53 * image library code, written in 1984. 54 * 55 * - Due to the heavy use of file seeks in Haeberli's code and the behaviour 56 * of Tcl_Seek on Windows when writing to files (sounds like smashing your 57 * HD), there is some workaround to use fseek and fwrite instead. 58 * See "#define TCLSEEK_WORKAROUND". 59 * 60 * ENDHEADER 61 * 62 * $Id: sgi.c 251 2010-04-28 13:28:28Z nijtmans $ 63 * 64 */ 65 66/* #define DEBUG_LOCAL */ 67 68/* 69 * Generic initialization code, parameterized via CPACKAGE and PACKAGE. 70 */ 71 72#include "init.c" 73 74 75#ifdef WIN32 76# define TCLSEEK_WORKAROUND 77#endif 78 79#ifdef TCLSEEK_WORKAROUND 80 static int ioMode = 0; /* Needed for Windows patch */ 81 82 static int MyWrite (Tcl_Channel chan, char *buf, int size) 83 { 84 if (1 == fwrite(buf, size, 1, (FILE *)chan)) { 85 return size; 86 } else { 87 return -1; 88 } 89 } 90 91 static int MyClose (Tcl_Interp *interp, Tcl_Channel chan) 92 { 93 if (0 == fclose((FILE *)chan)) { 94 return TCL_OK; 95 } else { 96 return TCL_ERROR; 97 } 98 } 99 100 static int MySeek (Tcl_Channel chan, int offset, int seekMode) 101 { 102 if (ioMode == 0) { /* Read mode */ 103 return Tcl_Seek (chan, offset, seekMode); 104 } else { 105 return fseek((FILE *)chan, offset, seekMode); 106 } 107 } 108 109# define MYCHANNEL Tcl_Channel 110# undef Tcl_Seek 111# define Tcl_Seek MySeek 112# undef Tcl_Write 113# define Tcl_Write MyWrite 114# define MYCLOSE MyClose 115#else 116# define MYCHANNEL Tcl_Channel 117# define MYCLOSE Tcl_Close 118#endif 119 120/* Some defines and typedefs for compatibility reasons. */ 121#define TRUE 1 122#define FALSE 0 123typedef unsigned char Boln; /* Boolean value: TRUE or FALSE */ 124typedef unsigned char UByte; /* Unsigned 8 bit integer */ 125typedef char Byte; /* Signed 8 bit integer */ 126typedef short Short; /* Signed 16 bit integer */ 127typedef unsigned short UShort; /* Unsigned 16 bit integer */ 128typedef int Int; /* Signed 32 bit integer */ 129typedef unsigned int UInt; /* Unsigned 32 bit integer */ 130 131 132/* Start of original code from SGI image library, slightly modified. */ 133 134#define IMAGIC 0x01DA 135 136/* colormap of images */ 137#define CM_NORMAL 0 /* file contains rows of values which 138 * are either RGB values (zsize == 3) 139 * or greyramp values (zsize == 1) */ 140#define CM_DITHERED 1 141#define CM_SCREEN 2 /* file contains data which is a screen 142 * image; getrow returns buffer which 143 * can be displayed directly with 144 * writepixels */ 145#define CM_COLORMAP 3 /* a colormap file */ 146 147#define TYPEMASK 0xff00 148#define BPPMASK 0x00ff 149#define ITYPE_UNCOMPRESSED 0x0000 150#define ITYPE_RLE 0x0100 151#define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE) 152#define ISUNCOMPRESSED(type) (((type) & 0xff00) == ITYPE_UNCOMPRESSED) 153#define BPP(type) ((type) & BPPMASK) 154#define RLE(bpp) (ITYPE_RLE | (bpp)) 155#define UNCOMPRESSED(bpp) (ITYPE_UNCOMPRESSED | (bpp)) 156#define IBUFSIZE(pixels) ((pixels+(pixels>>6))<<2) 157#define RLE_NOP 0x00 158 159#define ierror(p) (((p)->flags&_IOERR)!=0) 160#define ifileno(p) ((p)->file) 161#define getpix(p) (--(p)->cnt>=0 ? *(p)->ptr++ : ifilbuf(p)) 162#define putpix(p,x) (--(p)->cnt>=0 \ 163 ? ((int)(*(p)->ptr++=(unsigned)(x))) \ 164 : iflsbuf(p,(unsigned)(x))) 165 166/* The number of bytes of the IMAGE struct, which must be written to disk. 167 * All other information is needed only internally. It is filled with zeros 168 * on disk. */ 169#define RELEVANT_HEADER_BYTES 108 170 171typedef struct { 172 UShort imagic; /* stuff saved on disk . . */ 173 UShort type; 174 UShort dim; 175 UShort xsize; 176 UShort ysize; 177 UShort zsize; 178 UInt min; 179 UInt max; 180 UInt wastebytes; 181 char name[80]; 182 UInt colormap; 183 184 MYCHANNEL file; /* Stuff not stored in the file. */ 185 UShort flags; 186 Short dorev; 187 Short x; 188 Short y; 189 Short z; 190 Short cnt; 191 UShort *ptr; 192 UShort *base; 193 UShort *tmpbuf; 194 UInt offset; 195 UInt rleend; /* for rle images */ 196 UInt *rowstart; /* for rle images */ 197 Int *rowsize; /* for rle images */ 198 char dummy[512-146]; /* Fill bytes, so that this structure is greater 199 than 512 bytes */ 200} IMAGE; 201 202#if !defined (_IOWRT) 203# define _IOWRT 1 204#endif 205#if !defined (_IOREAD) 206# define _IOREAD 2 207#endif 208#if !defined (_IORW) 209# define _IORW 4 210#endif 211#if !defined (_IOERR) 212# define _IOERR 8 213#endif 214#if !defined (_IOEOF) 215# define _IOEOF 16 216#endif 217 218static int img_badrow(IMAGE *image, unsigned int y, unsigned int z); 219static int img_write(IMAGE *image, char *buffer,int count); 220static int img_writeheader(IMAGE *image); 221static int iflush(IMAGE *image); 222static unsigned short *ibufalloc(IMAGE *image); 223static unsigned int img_optseek(IMAGE *image, unsigned int offset); 224static int imgopen(int, MYCHANNEL, IMAGE *, const char *,unsigned int, unsigned int, 225 unsigned int, unsigned int, unsigned int); 226static int getrow(IMAGE *image, unsigned short *buffer, 227 unsigned int y, unsigned int z); 228static int putrow(IMAGE *image, unsigned short *buffer, 229 unsigned int y, unsigned int z); 230 231/* error handler for the image library. If the iseterror() routine 232 has been called, sprintf's the args into a string and calls the 233 error function. Otherwise calls fprintf with the args and then 234 exit. This allows 'old' programs to assume that no errors 235 ever need be worried about, while programs that know how and 236 want to can handle the errors themselves. Olson, 11/88 237*/ 238static void i_errhdlr(fmt, a1, a2, a3, a4) /* most args currently used is 2 */ 239char *fmt; 240{ 241 /* fprintf(stderr, fmt); */ 242 return; 243} 244 245/* 246 * isetname and isetcolormap - 247 * 248 * Paul Haeberli - 1984 249 * 250 */ 251 252static void isetname(IMAGE *image, const char *name) 253{ 254 strncpy(image->name,name,80); 255} 256 257/* This function is commented out because it is not used anywhere 258static void isetcolormap(IMAGE *image, int colormap) 259{ 260 image->colormap = colormap; 261} 262*/ 263 264static void cvtshorts( buffer, n) 265register unsigned short buffer[]; 266register int n; 267{ 268 register short i; 269 register int nshorts = n>>1; 270 register unsigned short swrd; 271 272 for(i=0; i<nshorts; i++) { 273 swrd = *buffer; 274 *buffer++ = (swrd>>8) | (swrd<<8); 275 } 276} 277 278static void cvtlongs( buffer, n) 279register int buffer[]; 280register int n; 281{ 282 register short i; 283 register int nlongs = n>>2; 284 register int lwrd; 285 Byte *bytePtr; 286 287 bytePtr = (Byte *) buffer; 288 for(i=0; i<nlongs; i++) { 289 lwrd = buffer[i]; 290 *bytePtr = (Byte) (lwrd >> 24); bytePtr++; 291 *bytePtr = (Byte) (lwrd >> 16); bytePtr++; 292 *bytePtr = (Byte) (lwrd >> 8); bytePtr++; 293 *bytePtr = (Byte) (lwrd); bytePtr++; 294 } 295} 296 297static void cvtimage( buffer ) 298int buffer[]; 299{ 300 cvtshorts((unsigned short *)buffer,12); 301 cvtlongs(buffer+3,12); 302} 303 304/* 305 * iopen - 306 * 307 * Paul Haeberli - 1984 308 * 309 */ 310 311static unsigned short *ibufalloc(IMAGE *image) 312{ 313 return (unsigned short *)malloc(IBUFSIZE(image->xsize)); 314} 315 316static int imgOpenRead (MYCHANNEL file, IMAGE *image, const char *mode) 317{ 318#ifdef TCLSEEK_WORKAROUND 319 ioMode = 0; 320#endif 321 return imgopen (0, file, image, mode, 0, 0, 0, 0, 0); 322} 323 324static int imgOpenWrite (MYCHANNEL file, IMAGE *image, const char *mode, 325 unsigned int type, unsigned int dim, 326 unsigned int xsize, unsigned int ysize, unsigned int zsize) 327{ 328#ifdef TCLSEEK_WORKAROUND 329 ioMode = 1; 330#endif 331 return imgopen (0, file, image, mode, type, dim, xsize, ysize, zsize); 332} 333 334static int imgopen(int f, MYCHANNEL file, IMAGE *image, const char *mode, 335 unsigned int type, unsigned int dim, 336 unsigned int xsize, unsigned int ysize, unsigned int zsize) 337{ 338 register int rw; 339 int tablesize; 340 register int i, max; 341 342 rw = mode[1] == '+'; 343 if(rw) { 344 i_errhdlr("iopen: read/write mode not supported\n"); 345 return 0; 346 } 347 if (*mode=='w') { 348 image->type = type; 349 image->xsize = xsize; 350 image->ysize = 1; 351 image->zsize = 1; 352 if (dim>1) 353 image->ysize = ysize; 354 if (dim>2) 355 image->zsize = zsize; 356 if(image->zsize == 1) { 357 image->dim = 2; 358 if(image->ysize == 1) 359 image->dim = 1; 360 } else { 361 image->dim = 3; 362 } 363 image->min = 10000000; 364 image->max = 0; 365 isetname(image,"no name"); 366 image->wastebytes = 0; 367 if (512 != Tcl_Write (file, (char *)image, 512)) { 368 i_errhdlr("iopen: error on write of image header\n"); 369 return 0; 370 } 371 } else { 372 if (512 != Tcl_Read (file, (char *)image, 512)) { 373 i_errhdlr("iopen: error on read of image header\n"); 374 return 0; 375 } 376 if( ((image->imagic>>8) | ((image->imagic&0xff)<<8)) == IMAGIC ) { 377 image->dorev = 1; 378 cvtimage((int *)image); 379 } else 380 image->dorev = 0; 381 if (image->imagic != IMAGIC) { 382 i_errhdlr("iopen: bad magic in image file %x\n",image->imagic); 383 return 0; 384 } 385 } 386 if (rw) 387 image->flags = _IORW; 388 else if (*mode != 'r') 389 image->flags = _IOWRT; 390 else 391 image->flags = _IOREAD; 392 if(ISRLE(image->type)) { 393 tablesize = image->ysize*image->zsize*sizeof(int); 394 image->rowstart = (unsigned int *)malloc(tablesize); 395 image->rowsize = (int *)malloc(tablesize); 396 if( image->rowstart == 0 || image->rowsize == 0 ) { 397 i_errhdlr("iopen: error on table alloc\n"); 398 return 0; 399 } 400 image->rleend = 512L+2*tablesize; 401 if (*mode=='w') { 402 max = image->ysize*image->zsize; 403 for(i=0; i<max; i++) { 404 image->rowstart[i] = 0; 405 image->rowsize[i] = -1; 406 } 407 } else { 408 tablesize = image->ysize*image->zsize*sizeof(int); 409 Tcl_Seek (file, 512L, 0); 410 if (tablesize != Tcl_Read (file, (char *)image->rowstart, tablesize)) { 411 i_errhdlr("iopen: error on read of rowstart\n"); 412 return 0; 413 } 414 if(image->dorev) 415 cvtlongs(image->rowstart,tablesize); 416 if (Tcl_Read (file, (char *)image->rowsize, tablesize) != tablesize) { 417 i_errhdlr("iopen: error on read of rowsize\n"); 418 return 0; 419 } 420 if(image->dorev) 421 cvtlongs(image->rowsize,tablesize); 422 } 423 } 424 image->cnt = 0; 425 image->ptr = 0; 426 image->base = 0; 427 if( (image->tmpbuf = ibufalloc(image)) == 0 ) { 428 i_errhdlr("iopen: error on tmpbuf alloc %d\n",image->xsize); 429 return 0; 430 } 431 image->x = image->y = image->z = 0; 432 image->file = file; 433 image->offset = 512L; /* set up for img_optseek */ 434 Tcl_Seek (image->file, 512L, 0); 435 return 1; 436} 437 438 439/* 440 * iclose and iflush - 441 * 442 * Paul Haeberli - 1984 443 * 444 */ 445 446static int iclose(IMAGE *image) 447{ 448 int tablesize; 449 450 iflush(image); 451 img_optseek(image, 0); 452 if (image->flags&_IOWRT) { 453 if(image->dorev) 454 cvtimage((int *)image); 455 if ( !img_writeheader(image)) { 456 i_errhdlr("iclose: error on write of image header\n"); 457 return EOF; 458 } 459 if(image->dorev) 460 cvtimage((int *)image); 461 if(ISRLE(image->type)) { 462 img_optseek(image, 512L); 463 tablesize = image->ysize*image->zsize*sizeof(int); 464 if(image->dorev) 465 cvtlongs(image->rowstart,tablesize); 466 if (img_write(image,(char *)(image->rowstart),tablesize) != tablesize) { 467 i_errhdlr("iclose: error on write of rowstart\n"); 468 return EOF; 469 } 470 if(image->dorev) 471 cvtlongs(image->rowsize,tablesize); 472 if (img_write(image,(char *)(image->rowsize),tablesize) != tablesize) { 473 i_errhdlr("iclose: error on write of rowsize\n"); 474 return EOF; 475 } 476 } 477 } 478 if(image->base) { 479 free(image->base); 480 image->base = 0; 481 } 482 if(image->tmpbuf) { 483 free(image->tmpbuf); 484 image->tmpbuf = 0; 485 } 486 if(ISRLE(image->type)) { 487 free(image->rowstart); 488 image->rowstart = 0; 489 free(image->rowsize); 490 image->rowsize = 0; 491 } 492 return 0; 493} 494 495static int iflush(IMAGE *image) 496{ 497 unsigned short *base; 498 499 if ( (image->flags&_IOWRT) 500 && (base=image->base)!=NULL && (image->ptr-base)>0) { 501 if (putrow(image, base, image->y,image->z)!=image->xsize) { 502 image->flags |= _IOERR; 503 return(EOF); 504 } 505 } 506 return(0); 507} 508 509/* 510 * ifilbuf - 511 * 512 * Paul Haeberli - 1984 513 * 514 */ 515 516/* This function is commented out because it is not used anywhere 517static int ifilbuf(IMAGE *image) 518{ 519 if ((image->flags&_IOREAD) == 0) 520 return(EOF); 521 if (image->base==NULL) { 522 if ((image->base = ibufalloc(image)) == NULL) { 523 i_errhdlr("can't alloc image buffer\n"); 524 return EOF; 525 } 526 } 527 image->cnt = getrow(image,image->base,image->y,image->z); 528 image->ptr = image->base; 529 if (--image->cnt < 0) { 530 if (image->cnt == -1) { 531 image->flags |= _IOEOF; 532 if (image->flags & _IORW) 533 image->flags &= ~_IOREAD; 534 } else 535 image->flags |= _IOERR; 536 image->cnt = 0; 537 return -1; 538 } 539 if(++image->y >= image->ysize) { 540 image->y = 0; 541 if(++image->z >= image->zsize) { 542 image->z = image->zsize-1; 543 image->flags |= _IOEOF; 544 return -1; 545 } 546 } 547 return *image->ptr++ & 0xffff; 548} 549*/ 550 551/* 552 * iflsbuf - 553 * 554 * Paul Haeberli - 1984 555 * 556 */ 557 558/* This function is commented out because it is not used anywhere 559static unsigned int iflsbuf(IMAGE *image, unsigned int c) 560{ 561 register unsigned short *base; 562 register int n, rn; 563 564 if ((image->flags&_IOWRT)==0) 565 return(EOF); 566 if ((base=image->base)==NULL) { 567 if ((image->base=base=ibufalloc(image)) == NULL) { 568 i_errhdlr("flsbuf: error on buf alloc\n"); 569 return EOF; 570 } 571 rn = n = 0; 572 } else if ((rn = n = image->ptr - base) > 0) { 573 n = putrow(image,base,image->y,image->z); 574 if(++image->y >= image->ysize) { 575 image->y = 0; 576 if(++image->z >= image->zsize) { 577 image->z = image->zsize-1; 578 image->flags |= _IOEOF; 579 return -1; 580 } 581 } 582 } 583 image->cnt = image->xsize-1; 584 *base++ = c; 585 image->ptr = base; 586 if (rn != n) { 587 image->flags |= _IOERR; 588 return(EOF); 589 } 590 return(c); 591} 592*/ 593 594 595/* 596 * img_seek, img_write, img_read, img_optseek - 597 * 598 * Paul Haeberli - 1984 599 * 600 */ 601 602static unsigned int img_seek(IMAGE *image, unsigned int y, unsigned int z) 603{ 604 if(img_badrow(image,y,z)) { 605 i_errhdlr("img_seek: row number out of range\n"); 606 return EOF; 607 } 608 image->x = 0; 609 image->y = y; 610 image->z = z; 611 if(ISUNCOMPRESSED(image->type)) { 612 switch(image->dim) { 613 case 1: 614 return img_optseek(image, 512L); 615 case 2: 616 return img_optseek(image,512L+(y*image->xsize)*BPP(image->type)); 617 case 3: 618 return img_optseek(image, 619 512L+(y*image->xsize+z*image->xsize*image->ysize)* 620 BPP(image->type)); 621 default: 622 i_errhdlr("img_seek: weird dim\n"); 623 break; 624 } 625 } else if(ISRLE(image->type)) { 626 switch(image->dim) { 627 case 1: 628 return img_optseek(image, image->rowstart[0]); 629 case 2: 630 return img_optseek(image, image->rowstart[y]); 631 case 3: 632 return img_optseek(image, image->rowstart[y+z*image->ysize]); 633 default: 634 i_errhdlr("img_seek: weird dim\n"); 635 break; 636 } 637 } else 638 i_errhdlr("img_seek: weird image type\n"); 639 return((unsigned int)-1); 640} 641 642static int img_badrow(IMAGE *image, unsigned int y, unsigned int z) 643{ 644 if(y>=image->ysize || z>=image->zsize) 645 return 1; 646 else 647 return 0; 648} 649 650static int img_write(IMAGE *image, char *buffer,int count) 651{ 652 int retval; 653 654 retval = Tcl_Write (image->file, buffer, count); 655 if(retval == count) 656 image->offset += count; 657 else 658 image->offset = -1; 659 return retval; 660} 661 662static int img_writeheader(IMAGE *image) 663{ 664 int retval; 665 666 retval = Tcl_Write (image->file, (char *)image, RELEVANT_HEADER_BYTES); 667 if(retval == RELEVANT_HEADER_BYTES) 668 image->offset += sizeof (IMAGE); 669 else 670 image->offset = -1; 671 return retval; 672} 673 674static int img_read(IMAGE *image, char *buffer, int count) 675{ 676 int retval; 677 678 retval = Tcl_Read (image->file, buffer, count); 679 if (retval == count) 680 image->offset += count; 681 else 682 image->offset = -1; 683 return retval; 684} 685 686static unsigned int img_optseek(IMAGE *image, unsigned int offset) 687{ 688 if(image->offset != offset) { 689 image->offset = offset; 690 return ((unsigned int) Tcl_Seek (image->file,offset,0)); 691 } 692 return offset; 693} 694 695/* 696 * getpix and putpix - 697 * 698 * Paul Haeberli - 1984 699 * 700 */ 701 702#undef getpix 703#undef putpix 704 705/* These functions are commented out because they are not used anywhere 706static int getpix(IMAGE *image) 707{ 708 if(--(image)->cnt>=0) 709 return (int)(*(image)->ptr++); 710 else 711 return ifilbuf(image); 712} 713 714static unsigned int putpix(IMAGE *image, unsigned int pix) 715{ 716 if(--(image)->cnt>=0) 717 return (unsigned int)(*(image)->ptr++ = pix); 718 else 719 return iflsbuf(image,pix); 720} 721*/ 722 723/* 724 * img_getrowsize, img_setrowsize, img_rle_compact, img_rle_expand - 725 * 726 * Paul Haeberli - 1984 727 * 728 */ 729 730static int img_getrowsize(IMAGE *image) 731{ 732 switch(image->dim) { 733 case 1: 734 return image->rowsize[0]; 735 case 2: 736 return image->rowsize[image->y]; 737 case 3: 738 return image->rowsize[image->y+image->z*image->ysize]; 739 } 740 return -1; 741} 742 743static void img_setrowsize(IMAGE *image, int cnt, int y, int z) 744{ 745 int *sizeptr; 746 747 if(img_badrow(image,y,z)) 748 return; 749 switch(image->dim) { 750 case 1: 751 sizeptr = &image->rowsize[0]; 752 image->rowstart[0] = image->rleend; 753 break; 754 case 2: 755 sizeptr = &image->rowsize[y]; 756 image->rowstart[y] = image->rleend; 757 break; 758 case 3: 759 sizeptr = &image->rowsize[y+z*image->ysize]; 760 image->rowstart[y+z*image->ysize] = image->rleend; 761 break; 762 default: 763 i_errhdlr ("img_setrowsize: bad dim: %d\n", image->dim); 764 return; 765 } 766 if(*sizeptr != -1) 767 image->wastebytes += *sizeptr; 768 *sizeptr = cnt; 769 image->rleend += cnt; 770} 771 772#define docompact \ 773 while(iptr<ibufend) { \ 774 sptr = iptr; \ 775 iptr += 2; \ 776 while((iptr<ibufend)&&((iptr[-2]!=iptr[-1])||(iptr[-1]!=iptr[0])))\ 777 iptr++; \ 778 iptr -= 2; \ 779 count = iptr-sptr; \ 780 while(count) { \ 781 todo = count>126 ? 126:count; \ 782 count -= todo; \ 783 *optr++ = 0x80|todo; \ 784 while(todo--) \ 785 *optr++ = *sptr++; \ 786 } \ 787 sptr = iptr; \ 788 cc = *iptr++; \ 789 while( (iptr<ibufend) && (*iptr == cc) ) \ 790 iptr++; \ 791 count = iptr-sptr; \ 792 while(count) { \ 793 todo = count>126 ? 126:count; \ 794 count -= todo; \ 795 *optr++ = todo; \ 796 *optr++ = cc; \ 797 } \ 798 } \ 799 *optr++ = 0; 800 801static int img_rle_compact(unsigned short *expbuf, int ibpp, 802 unsigned short *rlebuf, int obpp, int cnt) 803{ 804 if(ibpp == 1 && obpp == 1) { 805 register unsigned char *iptr = (unsigned char *)expbuf; 806 register unsigned char *ibufend = iptr+cnt; 807 register unsigned char *sptr; 808 register unsigned char *optr = (unsigned char *)rlebuf; 809 register short todo, cc; 810 register int count; 811 812 docompact; 813 return optr - (unsigned char *)rlebuf; 814 } else if(ibpp == 1 && obpp == 2) { 815 register unsigned char *iptr = (unsigned char *)expbuf; 816 register unsigned char *ibufend = iptr+cnt; 817 register unsigned char *sptr; 818 register unsigned short *optr = rlebuf; 819 register short todo, cc; 820 register int count; 821 822 docompact; 823 return optr - rlebuf; 824 } else if(ibpp == 2 && obpp == 1) { 825 register unsigned short *iptr = expbuf; 826 register unsigned short *ibufend = iptr+cnt; 827 register unsigned short *sptr; 828 register unsigned char *optr = (unsigned char *)rlebuf; 829 register short todo, cc; 830 register int count; 831 832 docompact; 833 return optr - (unsigned char *)rlebuf; 834 } else if(ibpp == 2 && obpp == 2) { 835 register unsigned short *iptr = expbuf; 836 register unsigned short *ibufend = iptr+cnt; 837 register unsigned short *sptr; 838 register unsigned short *optr = rlebuf; 839 register short todo, cc; 840 register int count; 841 842 docompact; 843 return optr - rlebuf; 844 } else { 845 i_errhdlr("rle_compact: bad bpp: %d %d\n",ibpp,obpp); 846 return 0; 847 } 848} 849 850#define doexpand \ 851 while(1) { \ 852 pixel = *iptr++; \ 853 if ( !(count = (pixel & 0x7f)) ) \ 854 return; \ 855 if(pixel & 0x80) { \ 856 while(count--) \ 857 *optr++ = *iptr++; \ 858 } else { \ 859 pixel = *iptr++; \ 860 while(count--) \ 861 *optr++ = pixel; \ 862 } \ 863 } 864 865static void img_rle_expand(unsigned short *rlebuf, int ibpp, 866 unsigned short *expbuf, int obpp) 867{ 868 if(ibpp == 1 && obpp == 1) { 869 register unsigned char *iptr = (unsigned char *)rlebuf; 870 register unsigned char *optr = (unsigned char *)expbuf; 871 register unsigned short pixel,count; 872 873 doexpand; 874 } else if(ibpp == 1 && obpp == 2) { 875 register unsigned char *iptr = (unsigned char *)rlebuf; 876 register unsigned short *optr = expbuf; 877 register unsigned short pixel,count; 878 879 doexpand; 880 } else if(ibpp == 2 && obpp == 1) { 881 register unsigned short *iptr = rlebuf; 882 register unsigned char *optr = (unsigned char *)expbuf; 883 register unsigned short pixel,count; 884 885 doexpand; 886 } else if(ibpp == 2 && obpp == 2) { 887 register unsigned short *iptr = rlebuf; 888 register unsigned short *optr = expbuf; 889 register unsigned short pixel,count; 890 891 doexpand; 892 } else 893 i_errhdlr("rle_expand: bad bpp: %d %d\n",ibpp,obpp); 894} 895 896/* 897 * putrow, getrow - 898 * 899 * Paul Haeberli - 1984 900 * 901 */ 902 903static int putrow(IMAGE *image, unsigned short *buffer, 904 unsigned int y, unsigned int z) 905{ 906 register unsigned short *sptr; 907 register unsigned char *cptr; 908 register unsigned int x; 909 register unsigned int min, max; 910 register int cnt; 911 912 if( !(image->flags & (_IORW|_IOWRT)) ) 913 return -1; 914 if(image->dim<3) 915 z = 0; 916 if(image->dim<2) 917 y = 0; 918 if(ISUNCOMPRESSED(image->type)) { 919 switch(BPP(image->type)) { 920 case 1: 921 min = image->min; 922 max = image->max; 923 cptr = (unsigned char *)image->tmpbuf; 924 sptr = buffer; 925 for(x=image->xsize; x--;) { 926 *cptr = *sptr++; 927 if (*cptr > max) max = *cptr; 928 if (*cptr < min) min = *cptr; 929 cptr++; 930 } 931 image->min = min; 932 image->max = max; 933 img_seek(image,y,z); 934 cnt = image->xsize; 935 if (img_write(image,(char *)(image->tmpbuf),cnt) != cnt) 936 return -1; 937 else 938 return cnt; 939 /* NOTREACHED */ 940 941 case 2: 942 min = image->min; 943 max = image->max; 944 sptr = buffer; 945 for(x=image->xsize; x--;) { 946 if (*sptr > max) max = *sptr; 947 if (*sptr < min) min = *sptr; 948 sptr++; 949 } 950 image->min = min; 951 image->max = max; 952 img_seek(image,y,z); 953 cnt = image->xsize<<1; 954 if(image->dorev) 955 cvtshorts(buffer,cnt); 956 if (img_write(image,(char *)(buffer),cnt) != cnt) { 957 if(image->dorev) 958 cvtshorts(buffer,cnt); 959 return -1; 960 } else { 961 if(image->dorev) 962 cvtshorts(buffer,cnt); 963 return image->xsize; 964 } 965 /* NOTREACHED */ 966 967 default: 968 i_errhdlr("putrow: weird bpp\n"); 969 } 970 } else if(ISRLE(image->type)) { 971 switch(BPP(image->type)) { 972 case 1: 973 min = image->min; 974 max = image->max; 975 sptr = buffer; 976 for(x=image->xsize; x--;) { 977 if (*sptr > max) max = *sptr; 978 if (*sptr < min) min = *sptr; 979 sptr++; 980 } 981 image->min = min; 982 image->max = max; 983 cnt = img_rle_compact(buffer,2,image->tmpbuf,1,image->xsize); 984 img_setrowsize(image,cnt,y,z); 985 img_seek(image,y,z); 986 if (img_write(image,(char *)(image->tmpbuf),cnt) != cnt) 987 return -1; 988 else 989 return image->xsize; 990 /* NOTREACHED */ 991 992 case 2: 993 min = image->min; 994 max = image->max; 995 sptr = buffer; 996 for(x=image->xsize; x--;) { 997 if (*sptr > max) max = *sptr; 998 if (*sptr < min) min = *sptr; 999 sptr++; 1000 } 1001 image->min = min; 1002 image->max = max; 1003 cnt = img_rle_compact(buffer,2,image->tmpbuf,2,image->xsize); 1004 cnt <<= 1; 1005 img_setrowsize(image,cnt,y,z); 1006 img_seek(image,y,z); 1007 if(image->dorev) 1008 cvtshorts(image->tmpbuf,cnt); 1009 if (img_write(image,(char *)(image->tmpbuf),cnt) != cnt) { 1010 if(image->dorev) 1011 cvtshorts(image->tmpbuf,cnt); 1012 return -1; 1013 } else { 1014 if(image->dorev) 1015 cvtshorts(image->tmpbuf,cnt); 1016 return image->xsize; 1017 } 1018 /* NOTREACHED */ 1019 1020 default: 1021 i_errhdlr("putrow: weird bpp\n"); 1022 } 1023 } else 1024 i_errhdlr("putrow: weird image type\n"); 1025 return(-1); 1026} 1027 1028static int getrow(IMAGE *image, unsigned short *buffer, 1029 unsigned int y, unsigned int z) 1030{ 1031 register short i; 1032 register unsigned char *cptr; 1033 register unsigned short *sptr; 1034 register short cnt; 1035 1036 if( !(image->flags & (_IORW|_IOREAD)) ) 1037 return -1; 1038 if(image->dim<3) 1039 z = 0; 1040 if(image->dim<2) 1041 y = 0; 1042 img_seek(image, y, z); 1043 if(ISUNCOMPRESSED(image->type)) { 1044 switch(BPP(image->type)) { 1045 case 1: 1046 if (img_read(image,(char *)image->tmpbuf,image->xsize) 1047 != image->xsize) 1048 return -1; 1049 else { 1050 cptr = (unsigned char *)image->tmpbuf; 1051 sptr = buffer; 1052 for(i=image->xsize; i--;) 1053 *sptr++ = *cptr++; 1054 } 1055 return image->xsize; 1056 /* NOTREACHED */ 1057 1058 case 2: 1059 cnt = image->xsize<<1; 1060 if (img_read(image,(char *)(buffer),cnt) != cnt) 1061 return -1; 1062 else { 1063 if(image->dorev) 1064 cvtshorts(buffer,cnt); 1065 return image->xsize; 1066 } 1067 /* NOTREACHED */ 1068 1069 default: 1070 i_errhdlr("getrow: weird bpp\n"); 1071 break; 1072 } 1073 } else if(ISRLE(image->type)) { 1074 switch(BPP(image->type)) { 1075 case 1: 1076 if( (cnt = img_getrowsize(image)) == -1 ) 1077 return -1; 1078 if( img_read(image,(char *)(image->tmpbuf),cnt) != cnt ) 1079 return -1; 1080 else { 1081 img_rle_expand(image->tmpbuf,1,buffer,2); 1082 return image->xsize; 1083 } 1084 /* NOTREACHED */ 1085 1086 case 2: 1087 if( (cnt = img_getrowsize(image)) == -1 ) 1088 return -1; 1089 if( cnt != img_read(image,(char *)(image->tmpbuf),cnt) ) 1090 return -1; 1091 else { 1092 if(image->dorev) 1093 cvtshorts(image->tmpbuf,cnt); 1094 img_rle_expand(image->tmpbuf,2,buffer,2); 1095 return image->xsize; 1096 } 1097 /* NOTREACHED */ 1098 1099 default: 1100 i_errhdlr("getrow: weird bpp\n"); 1101 break; 1102 } 1103 } else 1104 i_errhdlr("getrow: weird image type\n"); 1105 return -1; 1106} 1107 1108/* End of original SGI image code */ 1109 1110/* Structure to hold information about the SGI file being processed. */ 1111typedef struct { 1112 IMAGE th; 1113 UByte *red, /* Pointers to step through scanlines */ 1114 *green, 1115 *blue, 1116 *matte; 1117 UByte *redScan, /* Buffer for one scanline: Red channel */ 1118 *greenScan, /* Buffer for one scanline: Green channel */ 1119 *blueScan, /* Buffer for one scanline: Blue channel */ 1120 *matteScan; /* Buffer for one scanline: Matte channel */ 1121 UByte *scanline; 1122 unsigned short *pixbuf; 1123} SGIFILE; 1124 1125/* This function determines at runtime, whether we have to switch bytes. 1126 The SGI image format expects data to be in big-endian format. */ 1127 1128static int isIntel (void) 1129{ 1130 unsigned long val = 513; 1131 /* On Intel (little-endian) systems this value is equal to "\01\02\00\00". 1132 On big-endian systems this value equals "\00\00\02\01" */ 1133 return memcmp(&val, "\01\02", 2) == 0; 1134} 1135 1136static void sgiClose (SGIFILE *tf) 1137{ 1138 if (tf->redScan) ckfree ((char *)tf->redScan); 1139 if (tf->greenScan) ckfree ((char *)tf->greenScan); 1140 if (tf->blueScan) ckfree ((char *)tf->blueScan); 1141 if (tf->matteScan) ckfree ((char *)tf->matteScan); 1142 if (tf->pixbuf) ckfree ((char *)tf->pixbuf); 1143 return; 1144} 1145 1146#define OUT Tcl_WriteChars (outChan, str, -1) 1147static void printImgInfo (IMAGE *th, const char *filename, const char *msg) 1148{ 1149 Tcl_Channel outChan; 1150 char str[256]; 1151 1152 outChan = Tcl_GetStdChannel (TCL_STDOUT); 1153 if (!outChan) { 1154 return; 1155 } 1156 sprintf(str, "%s %s\n", msg, filename); OUT; 1157 sprintf(str, "\tSize in pixel : %d x %d\n", th->xsize, th->ysize); OUT; 1158 sprintf(str, "\tNo. of channels : %d\n", (th->zsize)); OUT; 1159 sprintf(str, "\tBytes per pixel : %d\n", BPP(th->type)); OUT; 1160 sprintf(str, "\tCompression : %s\n", ISRLE(th->type)? "RLE": "None"); OUT; 1161 Tcl_Flush(outChan); 1162} 1163#undef OUT 1164 1165static Boln readHeader (tkimg_MFile *handle, IMAGE *th) 1166{ 1167 if (512 != tkimg_Read(handle, (char *)th, 512)) { 1168 return FALSE; 1169 } 1170 if( ((th->imagic>>8) | ((th->imagic&0xff)<<8)) == IMAGIC ) { 1171 th->dorev = 1; 1172 cvtimage((int *)th); 1173 } else { 1174 th->dorev = 0; 1175 } 1176 if (th->imagic != IMAGIC) { 1177 return FALSE; 1178 } 1179 1180 return TRUE; 1181} 1182 1183static Boln writeHeader(tkimg_MFile *handle, IMAGE *th, UInt type, UInt dim, 1184 UInt xsize, UInt ysize, UInt zsize) 1185{ 1186 if (!imgOpenWrite ((MYCHANNEL)handle->data, th, "w", 1187 type, dim, xsize, ysize, zsize)) 1188 return FALSE; 1189 return TRUE; 1190} 1191 1192static Boln readChannel (SGIFILE *tf, UByte *dest, Int sgichn, Int nchan, 1193 Int y, Int n) 1194{ 1195 unsigned short *src = tf->pixbuf; 1196 unsigned short *stop = src + n; 1197 1198 if (-1 == getrow (&tf->th, tf->pixbuf, y, sgichn)) 1199 return FALSE; 1200 1201 dest += sgichn; 1202 switch (BPP(tf->th.type)) { 1203 case 1: { /* 8-bit pixel values */ 1204 while (src < stop) { 1205 *dest = *(src++); 1206 dest += nchan; 1207 } 1208 break; 1209 } 1210 case 2: { /* 16-bit values will be linearly mapped to 8-bit. */ 1211 while (src < stop) { 1212 *dest = *(src++) >> 8; 1213 dest += nchan; 1214 } 1215 break; 1216 } 1217 } 1218 return TRUE; 1219} 1220 1221static Boln sgiReadScan (Tcl_Interp *interp, tkimg_MFile *handle, 1222 SGIFILE *tf, Int y) 1223{ 1224 Int nchan; 1225 1226 nchan = tf->th.zsize; 1227 1228 /* Read 1. channel: This is either the red or brightness channel. */ 1229 if (!readChannel (tf, tf->scanline, 0, nchan, y, tf->th.xsize)) { 1230 return FALSE; 1231 } 1232 1233 if ( nchan >= 3) { 1234 /* This is either a RGB or RGBA image. Read green and blue channels. */ 1235 if (!readChannel (tf, tf->scanline, 1, nchan, y, tf->th.xsize) || 1236 !readChannel (tf, tf->scanline, 2, nchan, y, tf->th.xsize)) 1237 return FALSE; 1238 } 1239 if (nchan > 3 || nchan == 2) { 1240 /* If nchan is 2, we have a brightness-alpha image, if nchan is 4, we 1241 have RGBA. */ 1242 if (!readChannel (tf, tf->scanline, nchan == 2? 1: 3, nchan, 1243 y, tf->th.xsize)) 1244 return FALSE; 1245 } 1246 return TRUE; 1247} 1248 1249static Boln writeChannel (SGIFILE *tf, UByte *src, Int sgichn, Int y, Int n) 1250{ 1251 unsigned short *dest = tf->pixbuf; 1252 UByte *stop = src + n; 1253 1254 while (src < stop) 1255 *(dest++) = *(src++); 1256 1257 if (-1 == putrow (&tf->th, tf->pixbuf, y, sgichn)) 1258 return FALSE; 1259 1260 return TRUE; 1261} 1262 1263static Boln sgiWriteScan(Tcl_Interp *interp, tkimg_MFile *handle, 1264 SGIFILE *tf, Int y) 1265{ 1266 if (!writeChannel (tf, tf->redScan, 0, y, tf->th.xsize) || 1267 !writeChannel (tf, tf->greenScan, 1, y, tf->th.xsize) || 1268 !writeChannel (tf, tf->blueScan, 2, y, tf->th.xsize)) 1269 return FALSE; 1270 1271 if (tf->th.zsize > 3) 1272 if (!writeChannel (tf, tf->matteScan, 3, y, tf->th.xsize)) 1273 return FALSE; 1274 return TRUE; 1275} 1276 1277/* 1278 * Here is the start of the standard functions needed for every image format. 1279 */ 1280 1281/* 1282 * Prototypes for local procedures defined in this file: 1283 */ 1284 1285static int ParseFormatOpts(Tcl_Interp *interp, Tcl_Obj *format, 1286 int *comp, int *verb, int *matte); 1287static int CommonMatch(tkimg_MFile *handle, int *widthPtr, 1288 int *heightPtr, IMAGE *sgiHeaderPtr); 1289static int CommonRead(Tcl_Interp *interp, tkimg_MFile *handle, 1290 const char *filename, Tcl_Obj *format, 1291 Tk_PhotoHandle imageHandle, int destX, int destY, 1292 int width, int height, int srcX, int srcY); 1293static int CommonWrite(Tcl_Interp *interp, 1294 const char *filename, Tcl_Obj *format, 1295 tkimg_MFile *handle, Tk_PhotoImageBlock *blockPtr); 1296 1297static int ParseFormatOpts (interp, format, comp, verb, matte) 1298 Tcl_Interp *interp; 1299 Tcl_Obj *format; 1300 int *comp; 1301 int *verb; 1302 int *matte; 1303{ 1304 static const char *const sgiOptions[] = {"-compression", "-verbose", "-matte"}; 1305 int objc, length, c, i, index; 1306 Tcl_Obj **objv; 1307 const char *compression, *verbose, *transp; 1308 1309 *comp = 1; 1310 *verb = 0; 1311 *matte = 1; 1312 1313 if (tkimg_ListObjGetElements(interp, format, &objc, &objv) != TCL_OK) 1314 return TCL_ERROR; 1315 if (objc) { 1316 compression = "rle"; 1317 verbose = "0"; 1318 transp = "1"; 1319 for (i=1; i<objc; i++) { 1320 if (Tcl_GetIndexFromObj(interp, objv[i], (CONST84 char *CONST86 *)sgiOptions, 1321 "format option", 0, &index) != TCL_OK) { 1322 return TCL_ERROR; 1323 } 1324 if (++i >= objc) { 1325 Tcl_AppendResult(interp, "No value for option \"", 1326 Tcl_GetStringFromObj (objv[--i], (int *) NULL), 1327 "\"", (char *) NULL); 1328 return TCL_ERROR; 1329 } 1330 switch(index) { 1331 case 0: 1332 compression = Tcl_GetStringFromObj(objv[i], (int *) NULL); 1333 break; 1334 case 1: 1335 verbose = Tcl_GetStringFromObj(objv[i], (int *) NULL); 1336 break; 1337 case 2: 1338 transp = Tcl_GetStringFromObj(objv[i], (int *) NULL); 1339 break; 1340 } 1341 } 1342 1343 c = compression[0]; length = strlen (compression); 1344 if ((c == 'n') && (!strncmp (compression, "none", length))) { 1345 *comp = ITYPE_UNCOMPRESSED; 1346 } else if ((c == 'r') && (!strncmp (compression, "rle",length))) { 1347 *comp = ITYPE_RLE; 1348 } else { 1349 Tcl_AppendResult(interp, "invalid compression mode \"", 1350 compression, "\": should be rle or none", (char *) NULL); 1351 return TCL_ERROR; 1352 } 1353 1354 c = verbose[0]; length = strlen (verbose); 1355 if (!strncmp (verbose, "1", length) || \ 1356 !strncmp (verbose, "true", length) || \ 1357 !strncmp (verbose, "on", length)) { 1358 *verb = 1; 1359 } else if (!strncmp (verbose, "0", length) || \ 1360 !strncmp (verbose, "false", length) || \ 1361 !strncmp (verbose, "off", length)) { 1362 *verb = 0; 1363 } else { 1364 Tcl_AppendResult(interp, "invalid verbose mode \"", verbose, 1365 "\": should be 1 or 0, on or off, true or false", 1366 (char *) NULL); 1367 return TCL_ERROR; 1368 } 1369 1370 c = transp[0]; length = strlen (transp); 1371 if (!strncmp (transp, "1", length) || \ 1372 !strncmp (transp, "true", length) || \ 1373 !strncmp (transp, "on", length)) { 1374 *matte = 1; 1375 } else if (!strncmp (transp, "0", length) || \ 1376 !strncmp (transp, "false", length) || \ 1377 !strncmp (transp, "off", length)) { 1378 *matte = 0; 1379 } else { 1380 Tcl_AppendResult(interp, "invalid alpha (matte) mode \"", verbose, 1381 "\": should be 1 or 0, on or off, true or false", 1382 (char *) NULL); 1383 return TCL_ERROR; 1384 } 1385 } 1386 return TCL_OK; 1387} 1388 1389static int ChnMatch( 1390 Tcl_Channel chan, 1391 const char *filename, 1392 Tcl_Obj *format, 1393 int *widthPtr, 1394 int *heightPtr, 1395 Tcl_Interp *interp 1396) { 1397 tkimg_MFile handle; 1398 1399 handle.data = (char *) chan; 1400 handle.state = IMG_CHAN; 1401 1402 return CommonMatch(&handle, widthPtr, heightPtr, NULL); 1403} 1404 1405static int ObjMatch( 1406 Tcl_Obj *data, 1407 Tcl_Obj *format, 1408 int *widthPtr, 1409 int *heightPtr, 1410 Tcl_Interp *interp 1411) { 1412 tkimg_MFile handle; 1413 1414 if (!tkimg_ReadInit(data, '\001', &handle)) { 1415 return 0; 1416 } 1417 return CommonMatch(&handle, widthPtr, heightPtr, NULL); 1418} 1419 1420static int CommonMatch(handle, widthPtr, heightPtr, sgiHeaderPtr) 1421 tkimg_MFile *handle; 1422 int *widthPtr; 1423 int *heightPtr; 1424 IMAGE *sgiHeaderPtr; 1425{ 1426 IMAGE th; 1427 1428 if (!sgiHeaderPtr) { 1429 if (!readHeader (handle, &th)) 1430 return 0; 1431 } else { 1432 if (!imgOpenRead ((MYCHANNEL)handle->data, &th, "r")) 1433 return 0; 1434 } 1435 1436 if (th.xsize <= 0 || th.ysize <= 0) 1437 return 0; 1438 1439 *widthPtr = th.xsize; 1440 *heightPtr = th.ysize; 1441 if (sgiHeaderPtr) 1442 *sgiHeaderPtr = th; 1443 return 1; 1444} 1445 1446static int ChnRead(interp, chan, filename, format, imageHandle, 1447 destX, destY, width, height, srcX, srcY) 1448 Tcl_Interp *interp; 1449 Tcl_Channel chan; 1450 const char *filename; 1451 Tcl_Obj *format; 1452 Tk_PhotoHandle imageHandle; 1453 int destX, destY; 1454 int width, height; 1455 int srcX, srcY; 1456{ 1457 tkimg_MFile handle; 1458 1459 handle.data = (char *) chan; 1460 handle.state = IMG_CHAN; 1461 1462 return CommonRead (interp, &handle, filename, format, 1463 imageHandle, destX, destY, 1464 width, height, srcX, srcY); 1465} 1466 1467#define BUFLEN 2048 1468 1469static int ObjRead (interp, data, format, imageHandle, 1470 destX, destY, width, height, srcX, srcY) 1471 Tcl_Interp *interp; 1472 Tcl_Obj *data; 1473 Tcl_Obj *format; 1474 Tk_PhotoHandle imageHandle; 1475 int destX, destY; 1476 int width, height; 1477 int srcX, srcY; 1478{ 1479 tkimg_MFile handle; 1480 char *tempFileName, tempFileNameBuffer[256]; 1481 char buffer[BUFLEN]; 1482 MYCHANNEL outchan; 1483 Tcl_Channel inchan; 1484 int count, retVal; 1485 1486 tkimg_ReadInit (data, '\001', &handle); 1487 1488 tempFileName = tmpnam(tempFileNameBuffer); 1489#ifdef TCLSEEK_WORKAROUND 1490 outchan = (Tcl_Channel)fopen (tempFileName, "wb"); 1491#else 1492 outchan = tkimg_OpenFileChannel (interp, tempFileName, 0644); 1493#endif 1494 if (!outchan) { 1495 return TCL_ERROR; 1496 } 1497 1498 count = tkimg_Read(&handle, buffer, BUFLEN); 1499 while (count == BUFLEN) { 1500 Tcl_Write (outchan, buffer, count); 1501 count = tkimg_Read(&handle, buffer, BUFLEN); 1502 } 1503 if (count>0) { 1504 Tcl_Write (outchan, buffer, count); 1505 } 1506 if (MYCLOSE (interp, outchan) == TCL_ERROR) { 1507 return TCL_ERROR; 1508 } 1509 1510 inchan = tkimg_OpenFileChannel (interp, tempFileName, 0); 1511 if (!inchan) { 1512 return TCL_ERROR; 1513 } 1514 1515 handle.data = (char *) inchan; 1516 handle.state = IMG_CHAN; 1517 1518 retVal = CommonRead (interp, &handle, tempFileName, format, imageHandle, 1519 destX, destY, width, height, srcX, srcY); 1520 if (Tcl_Close (interp, inchan) == TCL_ERROR) { 1521 return TCL_ERROR; 1522 } 1523 remove (tempFileName); 1524 return retVal; 1525} 1526 1527static int CommonRead (interp, handle, filename, format, imageHandle, 1528 destX, destY, width, height, srcX, srcY) 1529 Tcl_Interp *interp; /* Interpreter to use for reporting errors. */ 1530 tkimg_MFile *handle; /* The image file, open for reading. */ 1531 const char *filename; /* The name of the image file. */ 1532 Tcl_Obj *format; /* User-specified format object, or NULL. */ 1533 Tk_PhotoHandle imageHandle; /* The photo image to write into. */ 1534 int destX, destY; /* Coordinates of top-left pixel in 1535 * photo image to be written to. */ 1536 int width, height; /* Dimensions of block of photo image to 1537 * be written to. */ 1538 int srcX, srcY; /* Coordinates of top-left pixel to be used 1539 * in image being read. */ 1540{ 1541 Tk_PhotoImageBlock block; 1542 Int y, nchan; 1543 int fileWidth, fileHeight; 1544 int stopY, outY, outWidth, outHeight; 1545 SGIFILE tf; 1546 int compr, verbose, matte; 1547 int result = TCL_OK; 1548 1549 memset(&tf, 0, sizeof (SGIFILE)); 1550 if (ParseFormatOpts(interp, format, &compr, &verbose, &matte) != TCL_OK) { 1551 return TCL_ERROR; 1552 } 1553 1554 CommonMatch(handle, &fileWidth, &fileHeight, &tf.th); 1555 if (verbose) 1556 printImgInfo (&tf.th, filename, "Reading image:"); 1557 1558 if ((srcX + width) > fileWidth) { 1559 outWidth = fileWidth - srcX; 1560 } else { 1561 outWidth = width; 1562 } 1563 if ((srcY + height) > fileHeight) { 1564 outHeight = fileHeight - srcY; 1565 } else { 1566 outHeight = height; 1567 } 1568 if ((outWidth <= 0) || (outHeight <= 0) 1569 || (srcX >= fileWidth) || (srcY >= fileHeight)) { 1570 return TCL_OK; 1571 } 1572 1573 if (tkimg_PhotoExpand(interp, imageHandle, destX + outWidth, destY + outHeight) == TCL_ERROR) { 1574 return TCL_ERROR; 1575 } 1576 1577 nchan = tf.th.zsize; 1578 1579 tf.pixbuf = (UShort *) ckalloc (fileWidth * nchan * sizeof (UShort)); 1580 tf.scanline = (UByte *) ckalloc (fileWidth * nchan); 1581 1582 block.pixelSize = nchan; 1583 block.pitch = fileWidth * nchan; 1584 block.width = outWidth; 1585 block.height = 1; 1586 switch (nchan) { 1587 case 1: /* Brightness */ 1588 case 2: /* Brightness + Matte */ 1589 block.offset[0] = 0; 1590 block.offset[1] = 0; 1591 block.offset[2] = 0; 1592 block.offset[3] = matte? 1: 0; 1593 break; 1594 case 3: /* RGB */ 1595 case 4: /* RGB + Matte */ 1596 block.offset[0] = 0; 1597 block.offset[1] = 1; 1598 block.offset[2] = 2; 1599 block.offset[3] = matte? 3: 0; 1600 break; 1601 default: 1602 printf("Invalid number of channels: %d\n", (int) nchan); 1603 return TCL_ERROR; 1604 break; 1605 } 1606 block.pixelPtr = tf.scanline + srcX * nchan; 1607 1608 stopY = srcY + outHeight; 1609 outY = destY; 1610 1611 for (y=0; y<stopY; y++) { 1612 sgiReadScan (interp, handle, &tf, fileHeight-1-y); 1613 if (y >= srcY) { 1614 if (tkimg_PhotoPutBlock(interp, imageHandle, &block, destX, outY, outWidth, 1, matte? TK_PHOTO_COMPOSITE_OVERLAY: TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) { 1615 result = TCL_ERROR; 1616 break; 1617 } 1618 outY++; 1619 } 1620 } 1621 sgiClose (&tf); 1622 return result; 1623} 1624 1625static int ChnWrite (interp, filename, format, blockPtr) 1626 Tcl_Interp *interp; 1627 const char *filename; 1628 Tcl_Obj *format; 1629 Tk_PhotoImageBlock *blockPtr; 1630{ 1631 MYCHANNEL chan; 1632 tkimg_MFile handle; 1633 int result; 1634 1635#ifdef TCLSEEK_WORKAROUND 1636 chan = (Tcl_Channel)fopen(filename, "wb"); 1637#else 1638 chan = tkimg_OpenFileChannel (interp, filename, 0644); 1639#endif 1640 if (!chan) { 1641 return TCL_ERROR; 1642 } 1643 1644 handle.data = (char *) chan; 1645 handle.state = IMG_CHAN; 1646 1647 result = CommonWrite (interp, filename, format, &handle, blockPtr); 1648 if (MYCLOSE(interp, chan) == TCL_ERROR) { 1649 return TCL_ERROR; 1650 } 1651 return result; 1652} 1653 1654static int StringWrite( 1655 Tcl_Interp *interp, 1656 Tcl_Obj *format, 1657 Tk_PhotoImageBlock *blockPtr 1658) { 1659 tkimg_MFile handle; 1660 int result; 1661 Tcl_DString data; 1662 Tcl_Channel inchan; 1663 MYCHANNEL outchan; 1664 char *tempFileName, tempFileNameBuffer[256]; 1665 char buffer[BUFLEN]; 1666 int count; 1667 1668 Tcl_DStringInit(&data); 1669 tempFileName = tmpnam(tempFileNameBuffer); 1670#ifdef TCLSEEK_WORKAROUND 1671 outchan = (Tcl_Channel)fopen(tempFileName, "wb"); 1672#else 1673 outchan = tkimg_OpenFileChannel (interp, tempFileName, 0644); 1674#endif 1675 if (!outchan) { 1676 return TCL_ERROR; 1677 } 1678 1679 handle.data = (char *) outchan; 1680 handle.state = IMG_CHAN; 1681 1682 result = CommonWrite(interp, tempFileName, format, &handle, blockPtr); 1683 if (MYCLOSE(interp, outchan) == TCL_ERROR) { 1684 return TCL_ERROR; 1685 } 1686 1687 tkimg_WriteInit(&data, &handle); 1688 1689 inchan = tkimg_OpenFileChannel(interp, tempFileName, 0); 1690 if (!inchan) { 1691 return TCL_ERROR; 1692 } 1693 1694 count = Tcl_Read(inchan, buffer, BUFLEN); 1695 while (count == BUFLEN) { 1696 tkimg_Write(&handle, buffer, count); 1697 count = Tcl_Read(inchan, buffer, BUFLEN); 1698 } 1699 if (count>0) { 1700 tkimg_Write(&handle, buffer, count); 1701 } 1702 if (Tcl_Close(interp, inchan) == TCL_ERROR) { 1703 return TCL_ERROR; 1704 } 1705 remove (tempFileName); 1706 tkimg_Putc(IMG_DONE, &handle); 1707 1708 if (result == TCL_OK) { 1709 Tcl_DStringResult(interp, &data); 1710 } else { 1711 Tcl_DStringFree(&data); 1712 } 1713 return result; 1714} 1715 1716static int CommonWrite (interp, filename, format, handle, blockPtr) 1717 Tcl_Interp *interp; 1718 const char *filename; 1719 Tcl_Obj *format; 1720 tkimg_MFile *handle; 1721 Tk_PhotoImageBlock *blockPtr; 1722{ 1723 Int x, y, bpp, nchan; 1724 Int redOffset, greenOffset, blueOffset, alphaOffset; 1725 UByte *pixelPtr, *rowPixPtr; 1726 SGIFILE tf; 1727 int compr, verbose, matte; /* Format options */ 1728 1729 memset (&tf, 0, sizeof (SGIFILE)); 1730 if (ParseFormatOpts(interp, format, &compr, &verbose, &matte) != TCL_OK) { 1731 return TCL_ERROR; 1732 } 1733 1734 bpp = 1; 1735 1736 redOffset = 0; 1737 greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; 1738 blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; 1739 alphaOffset = blockPtr->offset[0]; 1740 1741 if (alphaOffset < blockPtr->offset[2]) { 1742 alphaOffset = blockPtr->offset[2]; 1743 } 1744 if (++alphaOffset < blockPtr->pixelSize) { 1745 alphaOffset -= blockPtr->offset[0]; 1746 } else { 1747 alphaOffset = 0; 1748 } 1749 nchan = ((matte && alphaOffset)? 4: 3); 1750 1751 tf.redScan = (UByte *) ckalloc (blockPtr->width); 1752 tf.greenScan = (UByte *) ckalloc (blockPtr->width); 1753 tf.blueScan = (UByte *) ckalloc (blockPtr->width); 1754 tf.matteScan = (UByte *) ckalloc (blockPtr->width); 1755 tf.pixbuf = (UShort *) ckalloc (blockPtr->width * sizeof (UShort)); 1756 tf.th.imagic = IMAGIC; 1757 1758 if (!writeHeader(handle, &tf.th, 1759 compr? RLE(bpp): UNCOMPRESSED(bpp), 1760 nchan, blockPtr->width, blockPtr->height, nchan)) { 1761 return TCL_ERROR; 1762 } 1763 tf.th.dorev = isIntel(); 1764 1765 rowPixPtr = blockPtr->pixelPtr + blockPtr->offset[0]; 1766 for (y = blockPtr->height -1; y >=0; y--) { 1767 tf.red = tf.redScan; 1768 tf.green = tf.greenScan; 1769 tf.blue = tf.blueScan; 1770 tf.matte = tf.matteScan; 1771 pixelPtr = rowPixPtr; 1772 for (x = 0; x < blockPtr->width; x++) { 1773 *(tf.red++) = pixelPtr[redOffset]; 1774 *(tf.green++) = pixelPtr[greenOffset]; 1775 *(tf.blue++) = pixelPtr[blueOffset]; 1776 if (nchan == 4) { 1777 /* Have a matte channel and write it. */ 1778 *(tf.matte++) = pixelPtr[alphaOffset]; 1779 } 1780 pixelPtr += blockPtr->pixelSize; 1781 } 1782 if (!sgiWriteScan(interp, handle, &tf, y)) { 1783 sgiClose (&tf); 1784 return TCL_ERROR; 1785 } 1786 rowPixPtr += blockPtr->pitch; 1787 } 1788 if (verbose) 1789 printImgInfo (&tf.th, filename, "Saving image:"); 1790 1791 iclose (&tf.th); 1792 sgiClose (&tf); 1793 return TCL_OK; 1794} 1795