|
|
1.1 ! root 1: /* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved. */ ! 2: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. */ ! 3: /* The copyright notice does not imply actual or intended publication. */ ! 4: /* AUTHORS: */ ! 5: /* T. Pavlidis - ATT-BL MH - first versions */ ! 6: /* H. S. Baird - ATT-BL MH - first versions */ ! 7: ! 8: /* rlelib.c - subroutines for writing/reading run-length-encoded format files. ! 9: BUG: Uses system I/O for speed, but sacrifices machine-independence: ! 10: should use fioi.h macroes instead. ! 11: See rle.h for summary of rle file and format of public functions. ! 12: Writing a rle file: ! 13: fd=creat() ! 14: RLE_put_hdr(fd,hp) - once: allocate buffers, write header ! 15: RLE_put_Line(fd,lp) - repeatedly ! 16: RLE_close(fd) - once: flush and deallocate buffers ! 17: Reading a rle file: ! 18: fd=open() ! 19: RLE_open(fd,hp) - once: read header, 1st line into buffer ! 20: RLE_get_Line(l,r) - repeatedly (on EOF, deallocates buffer) ! 21: The user can read line-at-a-time or run-at-a-time, but should not intermix them: ! 22: line-at-a-time: ! 23: (RLE_Line *) RLE_get_Line(l,r) - return ptr to next line with some run ! 24: in the interval [l,r]; ! 25: read from opened file (NULL if EOF, abort on error) ! 26: allocates large buffer and frees it when done ! 27: run-at-a-time: ! 28: int RLE_get_Run(&R) - read next run into (RLE_Run) R ! 29: returns the line number (-1 for EOF, abort on ERROR) ! 30: does not allocate large buffer; ! 31: if only a few runs will be used, can be faster ! 32: */ ! 33: ! 34: #include <stdio.h> ! 35: #define LIBC_INCL 1 ! 36: #include "CPU.h" ! 37: #include "stdocr.h" ! 38: #include "rle.h" ! 39: ! 40: #define RLE_dbg F ! 41: #define dbg_rd F ! 42: #define dbg_wr F ! 43: ! 44: /* Treated as local static: */ ! 45: typedef struct RLE_global { ! 46: int fd; /* rle file descriptor */ ! 47: boolean eof; ! 48: int cy, cx; /* current line no., x-coord */ ! 49: short runs, nrun; /* no. runs, next run in current line */ ! 50: RLE_Line *lp; /* pointer to line (malloc space) */ ! 51: int bpl; /* maximum no. bytes in packed rle line */ ! 52: char *bf; /* I/O buffer (malloc space) */ ! 53: int bfsize; /* size of buffer */ ! 54: char *cp; /* cur. ptr, into bf */ ! 55: } RLE_global; ! 56: #define Init_RLE_global {0,F,-1,-1,0,0,NULL,0,NULL,0,NULL} ! 57: RLE_global _RLE = Init_RLE_global; ! 58: ! 59: RLE_put_hdr( fd, rhp, bufn ) ! 60: int fd; ! 61: RIC_hdr *rhp; ! 62: int bufn; /* minimum number of lines to buffer locally */ ! 63: { char hdr[100]; ! 64: int stat; ! 65: sprintf(hdr,"TYPE=rle\nWINDOW=%d %d %d %d\nRES=%d %d\n\n", ! 66: /* use half-open WINDOW convention: l&t closed, r&b open*/ ! 67: rhp->bx.a.x,rhp->bx.a.y,rhp->bx.b.x+1,rhp->bx.b.y+1, ! 68: rhp->res_x,rhp->res_y); ! 69: if((stat=write(fd,hdr,strlen(hdr)))!=strlen(hdr)) { ! 70: abort("rlelib: can't put hdr, stat %d",stat); ! 71: }; ! 72: _RLE.fd = fd; ! 73: _RLE.cy = rhp->bx.a.y-1; ! 74: _RLE.bpl = rhp->bx.b.x-rhp->bx.a.x+9; /* maximum bytes per line */ ! 75: _RLE.bfsize = bufn*_RLE.bpl; ! 76: if((_RLE.bf=(char *)malloc(_RLE.bfsize))==NULL) ! 77: abort("can't alloc _RLE.bf[%d]",_RLE.bfsize); ! 78: _RLE.cp = _RLE.bf; ! 79: } ! 80: ! 81: #define PUT(A,B) { if((A)<128) *(B)++ = (A); \ ! 82: else { *(B)++ = HIGH(A) | 0200; *(B)++ = LOW(A); } \ ! 83: } ! 84: ! 85: /* write out a non-blank line of runs */ ! 86: RLE_put_Line(fd,rlp) ! 87: int fd; /* file descr (already open) */ ! 88: RLE_Line *rlp; ! 89: { register char *bp; ! 90: short blank_lines_mny; /* the number of preceding blank lines, minus 1 */ ! 91: register RLE_Run *rp,*ep; ! 92: Scoor xsofar; ! 93: short bytes_mny; ! 94: int stat; /* I/O status */ ! 95: if((_RLE.bfsize-(_RLE.cp-_RLE.bf)) < _RLE.bpl) { ! 96: /* not enough room left in buffer for worst-case line */ ! 97: RLE_flush(); ! 98: }; ! 99: /* leave space for (short) bytes_mny count */ ! 100: bp=_RLE.cp+sizeof(short); ! 101: if((blank_lines_mny=(rlp->y-_RLE.cy-1))>0) /* blank lines were skipped */ { ! 102: PUT(0,bp); /* ``0 runs'' signals blank lines */ ! 103: PUT(blank_lines_mny,bp); ! 104: }; ! 105: _RLE.cy=rlp->y; ! 106: PUT(rlp->runs,bp); ! 107: xsofar=0; ! 108: for(rp=rlp->r,ep=rp+rlp->runs; rp!=ep; rp++) { ! 109: PUT(rp->xs-xsofar,bp); xsofar = rp->xs; ! 110: PUT(rp->xe-xsofar+1,bp); xsofar = rp->xe+1; ! 111: }; ! 112: /* go back & write no. bytes at top of line */ ! 113: *((short *) _RLE.cp) = bp-_RLE.cp-sizeof(short); ! 114: _RLE.cp = bp; ! 115: if(dbg_wr) err("RLE_put_Line y%d nh%d",_RLE.cy,bytes_mny-2); ! 116: }; ! 117: ! 118: /* write out a set of runs */ ! 119: RLE_put_Lines(fd,rlsp) ! 120: int fd; /* file descr (already open) */ ! 121: RLE_Lines *rlsp; ! 122: { int i; ! 123: RLE_Line *rlp; ! 124: for(i=0,rlp=rlsp->rla; i<rlsp->mny; i++,rlp++) ! 125: RLE_put_Line(fd,rlp); ! 126: } ! 127: ! 128: RLE_flush() ! 129: { int bytes; ! 130: int stat; ! 131: if((bytes=(_RLE.cp-_RLE.bf))>0) ! 132: if(stat=write(_RLE.fd,_RLE.bf,bytes)!=bytes) ! 133: abort("can't write _RLE.bf[%d], status %d",bytes,stat); ! 134: _RLE.cp = _RLE.bf; ! 135: } ! 136: ! 137: RLE_close(fd) ! 138: int fd; ! 139: { RLE_flush(); ! 140: if(_RLE.bf!=NULL) free(_RLE.bf); ! 141: _RLE.bf = _RLE.cp = NULL; ! 142: _RLE.bfsize = 0; ! 143: } ! 144: ! 145: /* ``open'' RLE_file for reading: ! 146: save filedes, read header, and read first line into buffer */ ! 147: boolean RLE_open( fd, hp ) ! 148: int fd; ! 149: RIC_hdr *hp; ! 150: { _RLE.fd = fd; ! 151: /* read header */ ! 152: RLE_get_hdr( fd, hp ); ! 153: if(_RLE.bf!=NULL) free(_RLE.bf); ! 154: _RLE.bfsize = _RLE.bpl; ! 155: if((_RLE.bf=(char *)malloc(_RLE.bfsize))==NULL) ! 156: abort("can't alloc _RLE.bf[%d]",_RLE.bfsize); ! 157: /* read first non-blank line */ ! 158: _RLE.cy = hp->bx.a.y-1; ! 159: if (!RLE_rdbf()) return(F); ! 160: _RLE.eof = F; ! 161: return(T); ! 162: } ! 163: ! 164: /* read next short from rle-line buffer, updating arg ptr */ ! 165: short RLE_gshort(p) ! 166: char **p; ! 167: { register n; ! 168: register char *q; ! 169: q = *p; ! 170: if((*q)&0200) { ! 171: n = (((*q & 0177)<<8)&077400) | (*(q+1) & 0377); ! 172: (*p)++; ! 173: } ! 174: else n = *q; ! 175: (*p)++; ! 176: return(n); ! 177: } ! 178: ! 179: /* system I/O variation on fgets(3), except it replaces \n with \0, ! 180: and returns the number of chars read (including \0) */ ! 181: int RLE_fgets(bf,max,fd) ! 182: char *bf; ! 183: int max; ! 184: int fd; ! 185: { char *cp; ! 186: int stat,mny; ! 187: cp=bf; mny=0; ! 188: while(((stat=read(fd,cp,1))==1)&&(++mny<max)&&((*cp)!='\n')) cp++; ! 189: if(stat!=1) return(stat); ! 190: else if(mny>=max) return(-1); ! 191: *cp='\0'; ! 192: return(mny); ! 193: } ! 194: ! 195: /* read ascii header from rle file, convert to RIC_hdr, ! 196: return status: 1 OK, 0 EOF, -1 error */ ! 197: int RLE_get_hdr( fd, hp ) ! 198: int fd; /* should have been open'ed earlier */ ! 199: RIC_hdr *hp; ! 200: #define HL_MAX 80 ! 201: #define HTERM "=, \n" /* terminations for header words: "=,<sp><tab>" */ ! 202: { char *cp,*parm,hline[HL_MAX]; ! 203: int status,nrd; ! 204: if((status=RLE_fgets(hline,HL_MAX,fd))<=0) return(status); ! 205: while(strlen(hline)>1) { ! 206: if(RLE_dbg) err("hline \"%s\"",hline); ! 207: parm=strtok(hline,HTERM); ! 208: if(parm!=NULL&&strcmp(parm,"TYPE")==0) { ! 209: if((parm=strtok(0,HTERM))!=NULL ! 210: &&strcmp(parm,"rle")==0) ; ! 211: else return(-1); ! 212: } ! 213: else if(parm!=NULL&&strcmp(parm,"WINDOW")==0) { ! 214: /* assume half-open WINDOW: l&t closed, r&b open */ ! 215: if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.x=atoi(parm); ! 216: else return(-1); ! 217: if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.y=atoi(parm); ! 218: else return(-1); ! 219: if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.x=atoi(parm)-1; ! 220: else return(-1); ! 221: if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.y=atoi(parm)-1; ! 222: else return(-1); ! 223: } ! 224: else if(parm!=NULL&&strcmp(parm,"RES")==0) { ! 225: if((parm=strtok(0,HTERM))!=NULL) hp->res_x=atoi(parm); ! 226: else return(-1); ! 227: if((parm=strtok(0,HTERM))!=NULL) hp->res_y=atoi(parm); ! 228: else return(-1); ! 229: } ! 230: else return(-1); ! 231: if((status=RLE_fgets(hline,HL_MAX,fd))<=0) return(status); ! 232: }; ! 233: /* maximum possible no. bytes in a packed rle line */ ! 234: _RLE.bpl = hp->bpl = hp->bx.b.x-hp->bx.a.x+9; ! 235: if(dbg_rd) fprintf(stderr,"rlelib: RLE_get_hdr: %s\n",RIC_hdr_toa(hp)); ! 236: return(1); ! 237: } ! 238: ! 239: /* read the next run into *Rp, and return line number ! 240: (-1 for EOF, abort on error) */ ! 241: int RLE_get_Run( Rp ) ! 242: RLE_Run *Rp; ! 243: { if(_RLE.nrun >= _RLE.runs) { /* no more, try to read next line */ ! 244: if (!RLE_rdbf()) /* EOF */ return(-1); ! 245: }; ! 246: /* another run */ ! 247: Rp->xs = (_RLE.cx += RLE_gshort(&_RLE.cp)); ! 248: Rp->xe = (_RLE.cx += RLE_gshort(&_RLE.cp)) - 1; ! 249: _RLE.nrun++; ! 250: return(_RLE.cy); ! 251: } ! 252: ! 253: /* Return ptr to the next line with at least one run overlapping the margins ! 254: [lm,rm]. The reported runs are not trimmed to fit exactly within margins. ! 255: If no more lines, return NULL. On error, abort */ ! 256: RLE_Line *RLE_get_Line(lm,rm) ! 257: int lm, rm; /* left, right margins */ ! 258: { register int rr; /* runs read */ ! 259: register RLE_Run *rp; /* write ptr */ ! 260: ! 261: do { if(_RLE.eof) { ! 262: free(_RLE.lp); _RLE.lp = NULL; ! 263: free(_RLE.bf); _RLE.bf = NULL; ! 264: return(NULL); ! 265: }; ! 266: if(_RLE.lp==NULL) { /* allocate space for RLE_Line */ ! 267: _RLE.lp = (RLE_Line *) malloc(sizeof(RLE_Line)); ! 268: if(_RLE.lp==NULL) { ! 269: abort("rlelib: can't malloc RLE_Line (%d bytes)", ! 270: sizeof(RLE_Line)); ! 271: }; ! 272: }; ! 273: _RLE.lp->y = _RLE.cy; ! 274: /* guaranteed to be at least one run in line */ ! 275: rr=0; rp=_RLE.lp->r; _RLE.lp->runs=0; ! 276: /* skip runs that are outside left margin */ ! 277: do RLE_get_Run(rp); ! 278: while((rr++ < _RLE.runs) && (rp->xe < lm)); ! 279: /* accept runs until cross right margin */ ! 280: while(rp->xs <= rm) { ! 281: _RLE.lp->runs++; /* count accepted runs */ ! 282: if(rr++ >= _RLE.runs) break; ! 283: RLE_get_Run(++rp); ! 284: }; ! 285: /* look ahead to next line */ ! 286: if (!RLE_rdbf()) /* EOF */ _RLE.eof=T; ! 287: } ! 288: while(_RLE.lp->runs==0); /* as result of margins, some lines may empty */ ! 289: return(_RLE.lp); ! 290: } ! 291: ! 292: /* read next line buffer - return F if EOF, abort on error ! 293: sideffects: sets up _RLE.cp, _RLE.cy, _RLE.cx, _RLE.runs, _RLE.nrun */ ! 294: boolean RLE_rdbf() ! 295: { short nh; ! 296: if(dbg_rd) err("enter RLE_rdbf"); ! 297: /* get number of bytes holding RLE of a scan line */ ! 298: if( read(_RLE.fd,&nh,sizeof(short)) != sizeof(short)) { ! 299: return(F); /* normal EOF */ ! 300: }; ! 301: if( Readvax ) ! 302: nh = swapshortin( nh ); ! 303: if(dbg_rd) err("rlelib: RLE_rdbf: nh %d",nh); ! 304: if(nh > _RLE.bpl) { ! 305: abort("rlelib: too many bytes in line: %d > %d(_RLE.bpl)", ! 306: nh,_RLE.bpl); ! 307: }; ! 308: ! 309: /* get those bytes */ ! 310: if( read(_RLE.fd,_RLE.bf,nh) != nh) { ! 311: abort("rlelib: rle line truncated"); ! 312: }; ! 313: if(dbg_rd) { ! 314: int bi; ! 315: err("rlelib: RLE_rdbf: _RLE.bf[0-%d] octal:",nh-1); ! 316: for(bi=0;bi<nh;bi++) ! 317: fprintf(stderr," 0%o",0377&(_RLE.bf[bi])); ! 318: fprintf(stderr,"\n"); ! 319: }; ! 320: ! 321: /* decode the bytes */ ! 322: _RLE.cp = _RLE.bf; ! 323: _RLE.runs = RLE_gshort(&_RLE.cp); ! 324: if(dbg_rd) err("rlelib: _RLE.runs %d",_RLE.runs); ! 325: if(_RLE.runs==0) { /* blank lines seen */ ! 326: _RLE.cy += RLE_gshort(&_RLE.cp); ! 327: _RLE.runs = RLE_gshort(&_RLE.cp); ! 328: if(dbg_rd) ! 329: err("rlelib: _RLE.cy %d _RLE.runs %d",_RLE.cy,_RLE.runs); ! 330: }; ! 331: if(_RLE.runs>RLE_RUNS || _RLE.runs<1) { ! 332: abort("rlelib: illegal no. runs %d in line",_RLE.runs); ! 333: }; ! 334: _RLE.cy++; ! 335: if(dbg_rd) err("rlelib: RLE_rdbf: _RLE.runs %d _RLE.cy %d",_RLE.runs,_RLE.cy); ! 336: _RLE.cx = _RLE.nrun = 0; /* next run will be first */ ! 337: if(dbg_rd) err("rlelib: RLE_rdbf: T exit"); ! 338: return(T); ! 339: } ! 340: ! 341: /* brrl - compute a binary raster line from a run-length-encoded scanline. ! 342: runa[] is an array of shorts, grouped in pairs (xs,xe) to describe the starting ! 343: and ending index (inclusive) of each run of black pixels (1 bits). ! 344: xe >= xs > xe. The runs are in strictly ascending order on xs. ! 345: lm & rm are the left and right margin indices of pixels, outside of which the ! 346: pixels are forced to be white. rm >= lm. The `lm'th pixel is written ! 347: into the `olm'th bit of the output raster (olm>=0). ! 348: rasp[] is a raser line of chars; on entry, it is assumed to have been zeroed ! 349: out. rasp[0] holds the leftmost byte in the line and the 001 bit of each ! 350: byte is the leftmost bit in that byte. ! 351: The user must ensure that rasp[] is at least (rm-lm+olm+9)/8 bytes long. ! 352: Returns the number of black pixels in the raster line. ! 353: NOTE: this uses the ``little-endian'' convention, in which the leftmost pixel ! 354: in a byte is placed in the least-significant bit (0x01). See `brrlb()' below ! 355: for the alternative ``big-endian'' version. ! 356: */ ! 357: int brrl(runs,runa,lm,rm,olm,rasp) ! 358: int runs; /* number of run-segments in runa[] */ ! 359: short runa[]; /* array of run-segments [xs,xe] (pairs of short) */ ! 360: int lm,rm; /* left,right margin bit indices within raster */ ! 361: int olm; /* `lm'th input pixel will be written to `olm'th bit */ ! 362: char unsigned rasp[]; /* binary raster line (zeroed out on entry) */ ! 363: { int pixels,bi; ! 364: RLE_Run r,*rp,*re; ! 365: pixels = 0; ! 366: re = (rp = (RLE_Run *) runa) + runs; ! 367: while(rp<re && rp->xe<lm) rp++; /* skip runs to the left of 'lm' */ ! 368: while(rp<re && rp->xs<=rm) { ! 369: /* truncate to margins */ ! 370: if((r.xs = rp->xs)<lm) r.xs = lm; ! 371: if((r.xe = rp->xe)>rm) r.xe = rm; ! 372: /* shift to output indices */ ! 373: r.xs += olm-lm; r.xe += olm-lm; ! 374: /** SLOW **/ ! 375: for(bi=r.xs; bi<=r.xe; bi++) rasp[bi/8] |= (01)<<(bi%8); ! 376: pixels += r.xe-r.xs+1; ! 377: rp++; ! 378: }; ! 379: return(pixels); ! 380: } ! 381: ! 382: /* ``big-endian'' version of brrl: bits are packed so that the leftmost ! 383: pixel is placed in the high-order bit (0x80) of each byte. ! 384: */ ! 385: int brrlb(runs,runa,lm,rm,olm,rasp) ! 386: int runs; ! 387: short runa[]; ! 388: int lm,rm,olm; ! 389: char unsigned rasp[]; ! 390: { int pixels,bi; ! 391: RLE_Run r,*rp,*re; ! 392: pixels = 0; ! 393: re = (rp = (RLE_Run *) runa) + runs; ! 394: while(rp<re && rp->xe<lm) rp++; /* skip runs to the left of 'lm' */ ! 395: while(rp<re && rp->xs<=rm) { ! 396: /* truncate to margins */ ! 397: if((r.xs = rp->xs)<lm) r.xs = lm; ! 398: if((r.xe = rp->xe)>rm) r.xe = rm; ! 399: /* shift to output indices */ ! 400: r.xs += olm-lm; r.xe += olm-lm; ! 401: /** SLOW **/ ! 402: for(bi=r.xs; bi<=r.xe; bi++) rasp[bi/8] |= (0200)>>(bi%8); ! 403: pixels += r.xe-r.xs+1; ! 404: rp++; ! 405: }; ! 406: return(pixels); ! 407: } ! 408: ! 409: /* crrl - compute a character raster line from a run-length-encoded scanline. ! 410: runa[] is an array of shorts, grouped in pairs (xs,xe) to describe the starting ! 411: and ending index (inclusive) of each run of black pixels (1 bits): xs<=xe. ! 412: The runs are in strictly ascending order on xs. lm & rm are the left and ! 413: right margin indices, outside of which pixels are forced to be white. rm >= lm. ! 414: rasp[] is a raster line, one unsigned char per pixel; rasp[0] holds the ! 415: leftmost pixel. The user must ensure that rasp[] is at least (rm-lm+1) ! 416: bytes long. Black pixels are encoded as 0, white as 255. Returns the number ! 417: of black pixels in the raster line. ! 418: */ ! 419: #define WHITE_pel 0377 ! 420: #define BLACK_pel 0000 ! 421: int crrl(runs,runa,lm,rm,rasp) ! 422: int runs; /* number of run-segments in runa[] */ ! 423: short runa[]; /* array of run-segments [xs,xe] (pairs of short) */ ! 424: int lm,rm; /* left,right margin bit indices within raster */ ! 425: unsigned char rasp[]; /* char raster line */ ! 426: { int pixels,bi,wid; ! 427: RLE_Run r,*rp,*re; ! 428: unsigned char *cp,*ep; ! 429: wid=rm-lm+1; ! 430: memset(rasp,WHITE_pel,wid); ! 431: re = (rp = (RLE_Run *) runa) + runs; ! 432: while(rp<re&&rp->xe<lm) rp++; /* skip runs to the left of 'lm' */ ! 433: if(rp>=re) return(0); ! 434: ! 435: r = *rp; r.xs -= lm; r.xe -= lm; ! 436: pixels = 0; ! 437: do { /* truncate left,right margin */ ! 438: if(r.xs<0) r.xs = 0; ! 439: if(r.xe>(wid-1)) r.xe = wid-1; ! 440: /* write r into raster line */ ! 441: pixels += (r.xe-r.xs+1); ! 442: for(cp=rasp+r.xs,ep=rasp+r.xe; cp<=ep; cp++) *cp = BLACK_pel; ! 443: /* step to next run */ ! 444: r = *(++rp); r.xs -= lm; r.xe -= lm; ! 445: } ! 446: while(r.xs<=(wid-1)&&rp<re); ! 447: return(pixels); ! 448: } ! 449: ! 450: /* trcr - threshold & run-length-encode a char raster line. `rasp' is a raster ! 451: line, one unsigned char per pixel: rasp[0] is the leftmost pixel in the line. ! 452: Pixels with value < 'thresh' are translated to black, else white. ! 453: Analyzes the line into a series of runs of `1's, placing them into array ! 454: `runs'. Observes margins: starts at `lm' bit and continues through `rm'; ! 455: bits outside the margins are assumed 0. A `run' is two shorts (the starting & ! 456: ending indices of the run of `1's, inclusive). The indices are shifted ! 457: so that the `lm'th pixel goes to run index `olm'. Returns the number of runs. ! 458: NOTE: The user must ensure that: (1) margins fall within `rasp[]'; ! 459: (2) `runp[]' is big enough to hold the worst-case no. of runs that can result ! 460: ((rm-lm+2)/2). The contents of the raster-line are unmodified. ! 461: */ ! 462: int trcr(rasp,lm,rm,olm,thresh,runp) ! 463: char unsigned rasp[]; /* binary raster line (with 1 extra byte at end) */ ! 464: int lm,rm; /* left,right margin indices within raster */ ! 465: int olm; /* `lm' pixel goes to `olm' run index */ ! 466: int thresh; ! 467: short runp[]; /* array of run-segments [xs,xe] (pairs of short) */ ! 468: #define dbg_trcr (T) ! 469: { unsigned char *cp,*ep; ! 470: short x,*xp; ! 471: int cv,pv; /* current,prior binary pixel value */ ! 472: ep=(cp=rasp+lm)+rm; x=olm; xp=runp; ! 473: pv=0; /* assume pixels left of 'lm' are 0 */ ! 474: while (cp<=ep) { ! 475: if((*cp)<thresh) { ! 476: /* black pixel */ ! 477: cv=1; ! 478: if(pv==0) { *xp = x; xp++; }; ! 479: } ! 480: else { /* white pixel */ ! 481: cv=0; ! 482: if(pv==1) { *xp = x-1; xp++; }; ! 483: }; ! 484: pv=cv; x++; ! 485: cp++; ! 486: }; ! 487: if(pv==1) { *xp = x-1; xp++; }; /* assume pixels right of 'rm' is 0 */ ! 488: return((xp-runp)/2); ! 489: } ! 490: ! 491: /* Transform a sequence of rle-lines using trimming, offsetting, scaling, ! 492: truncation, and reverse-video. Scaling may lead to interpolation or ! 493: decimation of lines, so an input line may be mapped into 0, 1, or more ! 494: output lines. ! 495: Input lines may be buffered, and there may be latency. To flush buffers, ! 496: this must be called with NULL argument at end of the sequence. Each output ! 497: line will be passed to function `sink()', which returns 1 if OK and 0 to quit. Quits are passed back immediately with no latency. Sink's 1st arg RLE_Line ! 498: *l is a line of runs in output coordinates, whose `len' is the maximum length ! 499: of the line. l==NULL means end of sequence. ! 500: Return 1 if OK, 0 to quit. A copy of *l is passed to sink(). ! 501: a->sy is incremented for every line written to the sink, and is attached to ! 502: the output lines as *.y. ! 503: */ ! 504: int transform_rlel(l,a,sink,sa) ! 505: RLE_Line *l; /* NULL if end of sequence */ ! 506: Transform_rlel_arg *a; ! 507: int (*sink)(); /* takes args: (RLE_Line *), and int */ ! 508: VOID *sa; /* passed to sink() as 2nd arg */ ! 509: { RLE_Line m,r; ! 510: register RLE_Run *rp,*ep,*mp; ! 511: RLE_Run mr,mm,rr; ! 512: int rm; ! 513: int o_a_x,o_b_x; /* maximum output index */ ! 514: if(l==NULL) { ! 515: sink(NULL,sa); ! 516: return(1); ! 517: }; ! 518: m.len = l->len; ! 519: m.runs = l->runs; ! 520: if(a->ident) { ! 521: if(m.runs>0) memcpy(m.r,l->r,2*m.runs*sizeof(short)); ! 522: m.y = a->sy; ! 523: if(sink(&m,sa)==0) return(0); ! 524: else { a->sy++; ! 525: return(1); ! 526: }; ! 527: }; ! 528: /* maximum permissable output bounds */ ! 529: o_a_x = (int)((a->tr.a.x + a->off.x)*a->scl.x); ! 530: o_b_x = o_a_x + a->wh.x - 1; ! 531: if(a->sy<=((int)a->dy)) { ! 532: /* compute runs to be ouput: rp - input runs; mp - output runs*/ ! 533: mp=(m.r - 1); ! 534: for(ep=(rp=l->r)+l->runs; rp<ep; rp++) { ! 535: /* trim using a->tr */ ! 536: mr = *rp; ! 537: if(mr.xe < a->tr.a.x) /* off left margin */ continue; ! 538: if(mr.xs > a->tr.b.x) /* off right margin */ break; ! 539: if(mr.xs < a->tr.a.x) /* extends left too far */ ! 540: mr.xs=a->tr.a.x; ! 541: if(mr.xe > a->tr.b.x) /* extends right too far */ ! 542: mr.xe=a->tr.b.x; ! 543: ! 544: /* offset using a->off */ ! 545: mr.xs += a->off.x; ! 546: mr.xe += a->off.x; ! 547: ! 548: /* expand using a->scl */ ! 549: mr.xs = (int)(mr.xs*a->scl.x); ! 550: mr.xe = ((int)((mr.xe+1)*a->scl.x))-1; ! 551: if(mr.xe<mr.xs) mr.xe=mr.xs; ! 552: ! 553: /* truncate to maximum output width */ ! 554: if(mr.xe<o_a_x) /* off left margin */ continue; ! 555: if(mr.xs>o_b_x) /* off right margin */ break; ! 556: if(mr.xs<o_a_x) /* extends left too far */ mr.xs=o_a_x; ! 557: if(mr.xe>o_b_x) /* extends right too far */ mr.xe=o_b_x; ! 558: /* store */ ! 559: if(mp < m.r) /* first */ *(++mp) = mr; ! 560: else /* can merge with prior run? */ { ! 561: if(mp->xe >= (mr.xs-1)) /* yes */ mp->xe = mr.xe; ! 562: else /* no */ *(++mp) = mr; ! 563: }; ! 564: }; ! 565: m.runs = mp - m.r + 1; ! 566: m.len = a->wh.x; ! 567: do { m.y = a->sy; ! 568: if(a->rev) { ! 569: /* r = reverse-video(m) */ ! 570: rp=r.r; rr.xs=o_a_x; ! 571: for(ep=(mp=m.r)+m.runs; mp<ep; mp++) { ! 572: if(rr.xs<mp->xs) { ! 573: rr.xe=mp->xs-1; ! 574: *(rp++)=rr; ! 575: }; ! 576: rr.xs=mp->xe+1; ! 577: }; ! 578: if(rr.xs<=o_b_x) { ! 579: rr.xe=o_b_x; ! 580: *(rp++)=rr; ! 581: }; ! 582: r.runs = rp-r.r; ! 583: r.len = m.len; ! 584: r.y = m.y; ! 585: if(sink(&r,sa)==0) return(0); ! 586: } ! 587: else { if(sink(&m,sa)==0) return(0); }; ! 588: a->sy++; ! 589: } ! 590: while(a->sy<=((int)a->dy)); ! 591: }; ! 592: a->dy += a->scl.y; ! 593: return(1); ! 594: } ! 595: ! 596: /* Insert a (copy of) the given RLE_Line in the RLE_Lines */ ! 597: insert_rlel(rlp,rlsp) ! 598: RLE_Line *rlp; ! 599: RLE_Lines *rlsp; ! 600: { abort("insert_rlel: unimplemented"); ! 601: } ! 602: ! 603: err_RLE_line(s,rl) ! 604: char *s; /* name */ ! 605: RLE_Line *rl; ! 606: { RLE_Run *r; ! 607: int ri; ! 608: if(rl==NULL) fprintf(stderr,"RLEL %10s NULL\n",s); ! 609: else { fprintf(stderr,"RLEL %10s y%d r%d l%d: ", ! 610: s,rl->y,rl->runs,rl->len); ! 611: for(ri=0,r=rl->r;ri<rl->runs;ri++,r++) ! 612: fprintf(stderr,"[%d,%d] ",r->xs,r->xe); ! 613: fprintf(stderr,"\n"); ! 614: }; ! 615: } ! 616:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.