Annotation of researchv10no/cmd/bcp/rlelib.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.