Annotation of researchv10no/cmd/bcp/rlelib.c, revision 1.1.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.