|
|
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: /* H. S. Baird - ATT-BL MH - first versions */
6: /* T. J. ThompsonT - ATT-BL HO - extensions */
7:
8: /* bcp.c - translate among binary image file formats, optionally trimming,
9: shifting, scaling, and rotating the image on the fly. Scaling is by
10: arbitrary real factors, separately in X & Y. Rotation is still crude and
11: slow.
12: USAGE:
13: bcp [options...] [I [O]]
14: I/O:
15: If O is omitted, all output is concatenated to stdout.
16: If I is also omitted, all input is read from stdin.
17: If I is a filename, it is the sole input; but, if it is a directory name,
18: then every leaf of its file tree is processed in turn; and, in this case,
19: if O also is specified, it is forced to become the root directory
20: of an isomorphic tree of output files (this use of Unix file trees
21: may be defeated using compile-time option FILE_TREE).
22:
23: [PROPOSED: An input file may be a catenation of pages. These may vary
24: in TYPE and other parameters. They will all be translated to the same
25: output type, and catenated to one file, each with a complete translated
26: header. Generally, a complete picfile header must be repeated at the
27: top of each page: exceptions include TYPE=cdf, which packs pages in its
28: own peculiar way.]
29:
30: OPTIONS:
31: NOTE: lengths, distances, and pixel indices are assumed to be in
32: units of pixels (scanner units), unless one of "icpPs" is appended,
33: meaning inches, cm, points, picas, or (explicitly) scanner pixels.
34: This applies to option: -w (seems buggy).
35:
36: -B[io] read/write bitfile(9.5) format (doesn't use TYPE= header).
37: [doesn't run-length encode yet: may be bulky.]
38: -M write TYPE=bitmap format.
39: -P write Postscript format (only on Suns; by Tim Thompson, ATT-BL HO)
40: -Rx[,y] force output resolutions to x,y (overrides -xX[,Y]) (pixels/inch).
41: Requires a RES=X Y line in the header.
42: -R= Force the output resolution to be equal to the greater of
43: the input resolutions.
44: -S write Sun rasterfile format (only on Suns; by Tim Thompson,
45: ATT-BL HO)
46: -Tt when reading TYPE=dump, binarize the image by thresholding each
47: pixel value as follows: (pixel<t)? black: white. (default: -T128)
48: -Ww shrink-wrap output around black artwork, surrounding it with equal
49: margins of width w (pixels), then translate so that the left-top
50: corner of the margin box is at 0,0 (works only with TYPE=document-
51: image input). (w must be >= 0)
52: -Zx[,y] set input resolution to RES=x y (overriding existing RES, if any)
53: -b write binary format (TYPE=binary)
54: -d? trace to stderr:
55: -dR comment on any change in resolution
56: -dc point out oddities in cdf files which are, by default,
57: silently corrected
58: -dh file headers (a good first debugging step)
59: -dm margins
60: -dr runs (exhaustive, voluminous)
61: -ds status and summary statistics (brief)
62: -g31 write CCITT FAX Group 3 1-dim encoding
63: -31 ditto
64: -g32 write CCITT FAX Group 3 2-dim encoding (see also -k option)
65: -32 ditto
66: -g4 write CCITT FAX Group 4 encoding (the default output format)
67: -4 ditto
68: -kK set the 'k' for g32 encoding on output (default: -k4)
69: -oX,Y offset the result by X,Y (merely shift the bounding box)
70: -p write TYPE=dump NCHAN=1 format; input binary pixels
71: are mapped to grey as follows: (pixel==white)? 255: 0.
72: -r write rle format (this is Pavlidis' obsolescent OCR format)
73: -t[lrbN] top of the page is really at the left/right/bottom;
74: after all other transformations are carried out, the image
75: will be rotated to bring the real top of page to the top.
76: By arbitrary convention, the top-left corner of the rotated
77: image will be equal to the top-left corner of the image
78: resulting from all the other transformations.
79: [UNFINISHED, UNDER DEVELOPMENT: -tr & -tb; -tN, where N is a
80: numeric string, is interpreted as a counterclockwise rotation by
81: N degrees: for now, only handle +/-20 degrees. The present code
82: for -tN is slow and subject to aliasing.]
83: -v reverse video: swap black and white
84: -wL,T,R,B specify window to select:
85: (L,T) is the left-top (origin) and (R,B) the OPEN right-bottom
86: corner (i.e. the corner coordinates are not included.) A '%'
87: argument defaults to the input window parameter.
88: [NOTE: since non-zero L,T windows are still not everywhere well
89: supported (by pcp, met, etc), it might be best to shift the
90: new L,T to 0,0 on output -- but this is not done now.]
91: -xX[,Y] expansion factor(s), horizontally and vertically;
92: if only one is specified, they are assumed equal
93: (default: -x1.0,1.0) May be overridden by -Rx[,y].
94: Requires a RES=X Y line in the header.
95: DESCRIPTION
96: This translates among these formats of binary images:
97: ccitt-g31, ccitt-g32, ccitt-g4, picture (TYPE=dump NCHAN=1), binary, rle,
98: bitfile(9.5), cdf, Sun rasterfile (TYPE=bitmap), and Postscript. All require
99: a TYPE= header in picfile format (see below), except bitfile(9.5) (as a result,
100: to read these, must use special option: -Bi). Most require WINDOW=ox oy cx cy
101: and RES=x y header lines also.
102: Optionally, the image may be modified on the fly by the following
103: operations performed in this order:
104: trimming - a subset of the input image is selected (-w option)
105: shifting - the origin is shifted (-o)
106: scaling - real scaling factors are applied, in X & Y separately (-x, -R)
107: rotation - by 90, 180, 270 degrees - UNDER DEVELOPMENT (-t option)
108: reverse-video - swap black and white (-v option)
109: Note that scaling changes the effective digitizing resolution by arbitrary
110: real factors (expansion or contraction), in X and Y separately. Presently,
111: this is accomplished naively by replication or deletion of pixels. If it is
112: ever desired to apply more interesting image-processing techniques (such as
113: smoothing and resampling), the required changes may be safely confined to
114: functions transform_rlels() (in bcp.c) & transform_rlel() (in rlelib.c).
115: Accepts TYPE=document-image (or TYPE=dim), flattening its hierarchy,
116: and writes it out as a single page image.
117: PICFILE FORMAT (briefly summarized; see picture(5))
118: Each picture file comprises an ASCII header followed by binary data.
119: The header is terminated by two newlines (an empty line). A typical header is:
120: TYPE=ccitt-g4
121: WINDOW=0 0 640 480
122: RES=300 300
123: (note the final empty line)
124: TYPE must come first. The other lines may come in any order. WINDOW gives
125: the x,y coordinates of the upper left corner (inclusive) and lower right
126: corners (exclusive). Typically, an image of WxH pixels will be described
127: by WINDOW=0 0 W H. RES=X Y gives the digitizing resolution horizontally and
128: vertically, in integral pixels/inch. Supported TYPEs include:
129:
130: dump A two-dimensional array of pixel structures. NCHAN=1 is required:
131: one byte per pixel. On input, the grey pixel values are thresholded
132: to binary (see option -T). On output, black is 0 and white is 255.
133:
134: bitmap One bit/pixel, packed into bytes high-order bit first. Black is `1'.
135: Each horizontal row is padded to a 16-bit boundary with `0'.
136: (This is identical to Sun rasterfile format, except for the ASCII
137: header.)
138:
139: ccitt-g4 CCITT FAX Group 4 compressed image. Similarly, ccitt-g31 means
140: Group 3/1-D and ccitt-g32 means Group 3/2-D.
141:
142: (Obsolescent 112 formats:
143: rle A run-length coding, better for binary images (see rle.h).
144: binary 1 bit/pixel, packed into bytes low-order bit first. Black is `1'.
145: Each horizontal row is padded to a full byte with `0'.)
146:
147: NOTE: bitfile(9.5) doesn't use an ASCII header.
148:
149: (Odd formats in use outside 112, sometimes very heavily:
150: cdf supported on input only, and only the first page of several.
151: tiff not yet supported.)
152:
153: IMPLEMENTATION STATUS
154: CCITT FAX ``uncompressed'' (or, ``transparent'') mode is not implemented,
155: either while encoding or decoding.
156: Cdf is an input-only option; Sun rasterfile and Postscript are output-only options.
157: Postscript output is useful only for very small images.
158: Rotations are only partially implemented, and are slow.
159:
160: KNOWN BUGS (30 May 89)
161: WINDOW=OX OY CX CY where OX or OY are non-zero is not handled correctly
162: for every combination of file types.
163: Unit gets passed wrongly to vto_scoor().
164: Rle can't be both inout and output (design flaw: they share a buffer).
165: Beware off-by-one errors (top or bottom line omitted); has not been
166: carefully checked for all file type combinations.
167:
168: AUTHORS
169: Dec 1988 - Henry S. Baird (AT&T Bell Labs MH) - first working draft
170: Mar 1989 - Tim Thompson (BL HO) - extensions for SunOS, bug fixes, etc
171: */
172:
173: #include <stdio.h>
174: #include <string.h>
175: #include <ctype.h>
176: #include "CPU.h"
177: #define MAIN 1
178: #include "stdocr.h"
179: #include "rle.h"
180: #include "pic.h"
181: #include "Text.h"
182: /* Ugly stubs just to prevent Text.h dragging in many other *.h & *.o files */
183: Bfeats *alloc_bfeats(){}; free_bfeats(){}; Bfeats *dup_bfeats(){};
184: fwrb_bfeats(){}; frdb_bfeats(){}; fix_lag(){}; char *classid_toa(){};
185: #include "Bitmap.h"
186: #include "CCITT.h"
187: #include "bitio.h"
188: #if FILE_TREE
189: #include "Path.h"
190: #endif
191: #define CMDNAME "bcp"
192: #include "abort.h"
193:
194: double atof(),sin(),cos();
195: char *strchr();
196:
197: /* Runtime options values */
198: static struct {
199: boolean from_bitfile; /* -Bi */
200: boolean to_bitfile; /* -Bo */
201: boolean to_bitmap; /* -M */
202: boolean to_g31; /* -g31 or -31 */
203: boolean to_g32; /* -g32 or -32 */
204: boolean to_g4; /* -g4 or -4 */
205: boolean to_rle; /* -r */
206: boolean to_bin; /* -b */
207: boolean to_pic; /* -p */
208: boolean to_post; /* -P */
209: boolean to_rast; /* -S */
210: boolean omit_hdr; /* -O */
211: Sp out_res; /* -R (-1 = unspecified; -2 = force-equal) */
212: Scoor shrinkwrap; /* -W (-1 = unspecified) */
213: Sp in_res; /* -Z (SHRT_MIN,SHRT_MIN = unspecified) */
214: int g32_k; /* -k */
215: int metheus; /* -m */
216: Sp offset; /* -o */
217: boolean dbg_any;
218: boolean dbg_R; /* -dR */
219: boolean dbg_c; /* -dc */
220: boolean dbg_h; /* -dh */
221: boolean dbg_m; /* -dm */
222: boolean dbg_r; /* -dr */
223: boolean dbg_s; /* -ds */
224: boolean show; /* -s */
225: char top; /* -tT takes on values: 't', 'l', 'r', 'b', 'a' */
226: float top_angle; /* -t angular value (set if top=='a') (Radians) */
227: int thresh; /* -Tt */
228: boolean reverse; /* -v */
229: char *optarg_l; /* -w?,,, */
230: char *optarg_t; /* -w,?,, */
231: char *optarg_r; /* -w,,?, */
232: char *optarg_b; /* -w,,,? */
233: Bbx trim; /* output margins resulting from -w */
234: Pp expand; /* -x */
235: char *in_fn;
236: char *out_fn;
237: } _O = {
238: F, F, F, F, F, T, F, F, F, F, F,
239: F, {-1,-1}, -1, {SHRT_MIN,SHRT_MIN}, 4, -1, Init_Zero_Sp,
240: F, F, F, F, F, F, F, F,
241: 't',0.0,
242: 128,
243: F,
244: NULL, NULL, NULL, NULL,
245: Init_Max_Bbx,
246: {1.0,1.0},
247: NULL, NULL };
248:
249: parse_args(arc,arv)
250: int arc; char **arv;
251: { /* getopt support */
252: int optch;
253: extern int optind;
254: extern char *optarg;
255:
256: char *metheus_ev,metheus_digit;
257: char *fs;
258:
259: /* default metheus number */
260: if((metheus_ev=(char *)getenv("FB"))!=NULL) {
261: metheus_digit = metheus_ev[(int)strlen(metheus_ev)-1];
262: if((int)isdigit(metheus_digit)) {
263: _O.metheus = (metheus_digit - '0');
264: };
265: };
266:
267: while((optch=getopt(arc,arv,"B:MOPR:ST:W:Z:3:4bd:g:k:m:o:prst:vw:x:"))!=EOF)
268: switch(optch) {
269: case 'B':
270: switch(*optarg) {
271: case 'o':
272: _O.to_bitfile = T;
273: _O.to_g4 = F;
274: break;
275: case 'i':
276: _O.from_bitfile = T;
277: break;
278: default:
279: abort("option -B%s is illegal",optarg);
280: break;
281: };
282: break;
283: case 'M': _O.to_bitmap = T; _O.to_g4 = F; break;
284: case 'O': _O.omit_hdr = T; break;
285: case 'P':
286: #if CPU==SUN
287: _O.to_post = T; _O.to_g4 = F;
288: #else
289: abort("-P option available only on Suns");
290: #endif
291: break;
292: case 'R':
293: if(*optarg=='=') {
294: _O.out_res.x = _O.out_res.y = -2;
295: fs=NULL;
296: }
297: else if((fs=strtok(optarg,","))!=NULL) {
298: if(strcmp(fs,"%")!=0) {
299: _O.out_res.x = atoi(fs);
300: };
301: };
302: if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
303: if(strcmp(fs,"%")!=0) {
304: _O.out_res.y = atoi(fs);
305: };
306: }
307: else _O.out_res.y = _O.out_res.x;
308: break;
309: case 'S':
310: #if CPU==SUN
311: _O.to_rast = T; _O.to_g4 = F;
312: #else
313: abort("-S option available only on Suns");
314: #endif
315: break;
316: case 'T': _O.thresh=atoi(optarg); break;
317: case 'W': _O.shrinkwrap=atoi(optarg);
318: if(_O.shrinkwrap<0) {
319: err("-W%d must be >=0; force to -W0",
320: _O.shrinkwrap);
321: _O.shrinkwrap=0;
322: };
323: break;
324: case 'Z':
325: if((fs=strtok(optarg,","))!=NULL) {
326: if(strcmp(fs,"%")!=0) {
327: _O.in_res.x = atoi(fs);
328: };
329: };
330: if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
331: if(strcmp(fs,"%")!=0) {
332: _O.in_res.y = atoi(fs);
333: };
334: }
335: else _O.in_res.y = _O.in_res.x;
336: break;
337: case '3':
338: switch (*optarg) {
339: case '1':
340: _O.to_g31=T;
341: _O.to_g4=F;
342: break;
343: case '2':
344: _O.to_g32=T;
345: _O.to_g4=F;
346: break;
347: default:
348: abort("bad option: -g3%s",optarg);
349: break;
350: };
351: break;
352: case '4': _O.to_g4=T; break;
353: case 'b':
354: _O.to_bin=T;
355: _O.to_g4=F;
356: break;
357: case 'd':
358: _O.dbg_any=T;
359: switch(*optarg) {
360: case 'R': _O.dbg_R = T; break;
361: case 'c': _O.dbg_c = T; break;
362: case 'h': _O.dbg_h = T; break;
363: case 'm': _O.dbg_m = T; break;
364: case 'r': _O.dbg_r = T; break;
365: case 's': _O.dbg_s = T; break;
366: };
367: break;
368: case 'g':
369: switch (optarg[0]) {
370: case '3':
371: switch (optarg[1]) {
372: case '1':
373: _O.to_g31=T;
374: _O.to_g4=F;
375: break;
376: case '2':
377: _O.to_g32=T;
378: _O.to_g4=F;
379: break;
380: default:
381: abort("bad option: -g%s",optarg);
382: break;
383: };
384: break;
385: case '4': _O.to_g4=T; break;
386: default:
387: abort("bad option: -g%s",optarg);
388: break;
389: };
390: break;
391: case 'k': _O.g32_k = atoi(optarg); break;
392: case 'm': _O.metheus = atoi(optarg); break;
393: case 'o':
394: if((fs=strtok(optarg,","))!=NULL) {
395: if(strcmp(fs,"%")!=0)
396: _O.offset.x = atoi(fs);
397: };
398: if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
399: if(strcmp(fs,"%")!=0)
400: _O.offset.y = atoi(fs);
401: };
402: break;
403: case 'p':
404: _O.to_pic=T;
405: _O.to_g4=F;
406: break;
407: case 'r':
408: _O.to_rle = T;
409: _O.to_g4 = F;
410: break;
411: case 's': _O.show = T; break;
412: case 't': _O.top = *optarg;
413: if(strchr("0123456789.+-",_O.top)!=NULL) {
414: _O.top = 'a'; /* angular value */
415: _O.top_angle = atof(optarg)*DtoR;
416: };
417: break;
418: case 'v': _O.reverse = T; break;
419: case 'w':
420: if( (fs=strtok(optarg,","))!=NULL
421: && strlen(fs)>0 && strcmp(fs,"%")!=0 )
422: _O.optarg_l = strdup(fs);
423: if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL
424: && strlen(fs)>0 && strcmp(fs,"%")!=0 )
425: _O.optarg_t = strdup(fs);
426: if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL
427: && strlen(fs)>0 && strcmp(fs,"%")!=0 )
428: _O.optarg_r = strdup(fs);
429: if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL
430: && strlen(fs)>0 && strcmp(fs,"%")!=0 )
431: _O.optarg_b = strdup(fs);
432: break;
433: case 'x':
434: if((fs=strtok(optarg,","))!=NULL) {
435: if(strcmp(fs,"%")!=0) {
436: if(*fs=='/')
437: _O.expand.x = 1.0/atof(fs+1);
438: else _O.expand.x = atof(fs);
439: if(_O.expand.x<=0.0)
440: _O.expand.x=1.0;
441: };
442: };
443: if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
444: if(strcmp(fs,"%")!=0) {
445: if(*fs=='/')
446: _O.expand.y = 1.0/atof(fs+1);
447: else _O.expand.y = atof(fs);
448: if(_O.expand.y<=0.0)
449: _O.expand.y=1.0;
450: };
451: }
452: else _O.expand.y = _O.expand.x;
453: break;
454: default: break;
455: };
456: switch(arc-optind) {
457: case 2:
458: _O.out_fn = strdup(arv[optind+1]);
459: case 1:
460: _O.in_fn = strdup(arv[optind]);
461: case 0:
462: break;
463: default:
464: abort("<= two filenames expected");
465: break;
466: };
467: if(_O.show&&_O.metheus==-1) {
468: err("FB=/dev/omM not specified, using /dev/om0");
469: _O.metheus = 0;
470: };
471: }
472:
473: unimplemented()
474: { abort("unimplemented");
475: }
476:
477: typedef struct Copy_arg {
478: boolean bop; /* beginning of page */
479: PIC_hdr *ph;
480: int wid; /* bbx_wid(&(ph->bx)) (for speed) */
481: BITFILE *bf;
482: DST_table *tbl; /* for CCITT input */
483: int k; /* CCITT Group 3 2-D k */
484: int thresh; /* for input pic files */
485: RLE_Lines rles; /* for TYPE=document-image or TYPE=dim */
486: } Copy_arg;
487: #define Init_Copy_arg {T,NULL,INT_MIN,NULL,NULL,4,128,Init_RLE_Lines}
488: #if MAIN
489: Copy_arg empty_Copy_arg = Init_Copy_arg;
490: #else
491: extern Copy_arg empty_Copy_arg;
492: #endif
493:
494: /* SOURCES: return the next RLE_Line from the given file type, with run indices
495: shifted to lie within [ a->ph->bx.a.x, a->ph->bx.b.x ].
496: **** BUGS: not all handle non-zero a->ph->bx.a.x yet.
497: */
498:
499: /* Handles non-zero a->ph->bx.a.x. */
500: RLE_Line *cdf_mrlc_source(a)
501: Copy_arg *a;
502: #define dbg_cdf (0)
503: { static RLE_Line rl;
504: int n; /* no. pixels decoded */
505: int col; /* color: 0=white, 1=black */
506: int byte; /* input byte */
507: int nb; /* no. bytes read for this line */
508: int ni; /* nibble index: 0=1st (low-order), 1=2nd(high-order) */
509: int nib; /* current nibble */
510: int mult; /* multiplier for current nibble */
511: int run; /* no. pixels in current run */
512: RLE_Run *rp;
513: #define toggle_color() {if(col) col=0; else col=1;}
514: /* get next byte into `byte' */
515: #define getbyte() { \
516: if((byte=getc(a->ph->fp))==EOF) goto eof; nb++; \
517: if(dbg_cdf) err("byte0x%x",byte); \
518: }
519: /* get next nibble into `nib' */
520: #define getnib() { \
521: if(ni) { getbyte(); ni=0; nib=byte&0x0F; } \
522: else { ni=1; nib=(byte>>4); } \
523: if(dbg_cdf) err("nib0x%x byte0x%x ni%d",nib,byte,ni); \
524: }
525: /* get next run into `run' */
526: #define getrun() { \
527: run=0; mult=1; \
528: do {getnib(); run += mult * (nib&0x07); mult *= 8;} while(nib&0x08); \
529: if(dbg_cdf) err("run%d %c",run,((col)? 'B': 'W')); \
530: }
531: a->bop = F;
532: n=0; col=0; ni=1; nb=0; rp=rl.r;
533: do { getrun();
534: if(col) {/* black run */
535: if(run>0) { /* ... of >0 length */
536: rp->xs = a->ph->bx.a.x + n+1;
537: rp->xe = a->ph->bx.a.x + (n+=run);
538: if((rp-rl.r)>0 && ((rp-1)->xe >= rp->xs-1) ) {
539: if(_O.dbg_c) err("cdf_mrlc_source: abutting black runs [%d,%d] & [%d,%d] - merged",
540: (rp-1)->xs,(rp-1)->xe,
541: rp->xs,rp->xe );
542: /* merge with prior black run */
543: (rp-1)->xe = rp->xe;
544: }
545: else rp++;
546: }
547: else { /* zero-length black run */
548: if( _O.dbg_c && (rp-rl.r)>0 )
549: err("cdf_mrlc_source: zero-length black run [%d,%d] in middle of line - ignored",
550: n,n);
551: };
552: }
553: else { /* white run */
554: n+=run;
555: };
556: toggle_color();
557: }
558: while(n<a->wid);
559: /* read 2 EOL nibbles */
560: getnib(); getnib();
561: rl.runs = rp - rl.r;
562: rl.len = a->wid;
563: if(rl.runs>0 && rl.r[rl.runs-1].xe>=a->wid) {
564: if(_O.dbg_c)
565: err("cdf_mrlc_source: run [%d,%d] in line of length %d - truncated",
566: rl.r[rl.runs-1].xs,rl.r[rl.runs-1].xe,a->wid);
567: rl.r[rl.runs-1].xe = a->wid-1;
568: if(rl.r[rl.runs-1].xs>rl.r[rl.runs-1].xe) {
569: rl.runs--;
570: };
571: };
572: rl.y = a->ph->cy++;
573: if(_O.dbg_r) nerr_RLE_Line("cdf_source: ",&rl);
574: return(&rl);
575:
576: eof: if(dbg_cdf)
577: err("cdf_mrlc_source: unexpected EOF, input line %d",a->ph->cy);
578: return(NULL);
579: }
580:
581: int no_runs_of_page(p)
582: Page *p;
583: { int runs;
584: runs = 0;
585: runs += no_runs_of_blocks(&p->bks);
586: runs += no_runs_of_txtlns(&p->ls);
587: runs += no_runs_of_words(&p->ws);
588: runs += no_runs_of_chars(&p->cs);
589: runs += no_runs_of_blobs(&p->bs);
590: return(runs);
591: }
592:
593: int runs_of_page(p,ra,max)
594: Page *p;
595: RLE_Yrun *ra;
596: int max;
597: { int runs;
598: runs = 0;
599: runs += runs_of_blocks(&p->bks,ra,max);
600: runs += runs_of_txtlns(&p->ls,ra+runs,max-runs);
601: runs += runs_of_words(&p->ws,ra+runs,max-runs);
602: runs += runs_of_chars(&p->cs,ra+runs,max-runs);
603: runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
604: return(runs);
605: }
606:
607: int no_runs_of_blocks(p)
608: Blocks *p;
609: { int runs;
610: Block *pp,**ppp;
611: runs = 0;
612: if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
613: runs += no_runs_of_block(pp);
614: return(runs);
615: }
616:
617: int runs_of_blocks(p,ra,max)
618: Blocks *p;
619: RLE_Yrun *ra;
620: int max;
621: { int runs;
622: Block *pp,**ppp;
623: runs = 0;
624: if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
625: runs += runs_of_block(pp,ra+runs,max-runs);
626: return(runs);
627: }
628:
629: int no_runs_of_block(p)
630: Block *p;
631: { int runs;
632: runs = 0;
633: runs += no_runs_of_txtlns(&p->ls);
634: runs += no_runs_of_words(&p->ws);
635: runs += no_runs_of_chars(&p->cs);
636: runs += no_runs_of_blobs(&p->bs);
637: return(runs);
638: }
639:
640: int runs_of_block(p,ra,max)
641: Block *p;
642: RLE_Yrun *ra;
643: int max;
644: { int runs;
645: runs = 0;
646: runs += runs_of_txtlns(&p->ls,ra+runs,max-runs);
647: runs += runs_of_words(&p->ws,ra+runs,max-runs);
648: runs += runs_of_chars(&p->cs,ra+runs,max-runs);
649: runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
650: return(runs);
651: }
652:
653: int no_runs_of_txtlns(p)
654: Txtlns *p;
655: { int runs;
656: Txtln *pp,**ppp;
657: runs = 0;
658: if(p->mny>0) for(pp= *(ppp=p->lpa); pp!=NULL; pp= *(++ppp))
659: runs += no_runs_of_txtln(pp);
660: return(runs);
661: }
662:
663: int runs_of_txtlns(p,ra,max)
664: Txtlns *p;
665: RLE_Yrun *ra;
666: int max;
667: { int runs;
668: Txtln *pp,**ppp;
669: runs = 0;
670: if(p->mny>0) for(pp= *(ppp=p->lpa); pp!=NULL; pp= *(++ppp))
671: runs += runs_of_txtln(pp,ra+runs,max-runs);
672: return(runs);
673: }
674:
675: int no_runs_of_txtln(p)
676: Txtln *p;
677: { int runs;
678: runs = 0;
679: runs += no_runs_of_words(&p->ws);
680: runs += no_runs_of_chars(&p->cs);
681: runs += no_runs_of_blobs(&p->bs);
682: return(runs);
683: }
684:
685: int runs_of_txtln(p,ra,max)
686: Txtln *p;
687: RLE_Yrun *ra;
688: int max;
689: { int runs;
690: runs = 0;
691: runs += runs_of_words(&p->ws,ra+runs,max-runs);
692: runs += runs_of_chars(&p->cs,ra+runs,max-runs);
693: runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
694: return(runs);
695: }
696:
697: int no_runs_of_words(p)
698: Words *p;
699: { int runs;
700: Word *pp,**ppp;
701: runs = 0;
702: if(p->mny>0) for(pp= *(ppp=p->wpa); pp!=NULL; pp= *(++ppp))
703: runs += no_runs_of_word(pp);
704: return(runs);
705: }
706:
707: int runs_of_words(p,ra,max)
708: Words *p;
709: RLE_Yrun *ra;
710: int max;
711: { int runs;
712: Word *pp,**ppp;
713: runs = 0;
714: if(p->mny>0) for(pp= *(ppp=p->wpa); pp!=NULL; pp= *(++ppp))
715: runs += runs_of_word(pp,ra+runs,max-runs);
716: return(runs);
717: }
718:
719: int no_runs_of_word(p)
720: Word *p;
721: { int runs;
722: runs = 0;
723: runs += no_runs_of_chars(&p->cs);
724: runs += no_runs_of_blobs(&p->bs);
725: return(runs);
726: }
727:
728: int runs_of_word(p,ra,max)
729: Word *p;
730: RLE_Yrun *ra;
731: int max;
732: { int runs;
733: runs = 0;
734: runs += runs_of_chars(&p->cs,ra+runs,max-runs);
735: runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
736: return(runs);
737: }
738:
739: int no_runs_of_chars(p)
740: Chars *p;
741: { int runs;
742: Char *pp,**ppp;
743: runs = 0;
744: if(p->mny>0) for(pp= *(ppp=p->cpa); pp!=NULL; pp= *(++ppp))
745: runs += no_runs_of_char(pp);
746: return(runs);
747: }
748:
749: int runs_of_chars(p,ra,max)
750: Chars *p;
751: RLE_Yrun *ra;
752: int max;
753: { int runs;
754: Char *pp,**ppp;
755: runs = 0;
756: if(p->mny>0) for(pp= *(ppp=p->cpa); pp!=NULL; pp= *(++ppp))
757: runs += runs_of_char(pp,ra+runs,max-runs);
758: return(runs);
759: }
760:
761: int no_runs_of_blobs(p)
762: Blobs *p;
763: { int runs;
764: Blob *pp,**ppp;
765: runs = 0;
766: if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
767: runs += pp->runs;
768: return(runs);
769: }
770:
771: int runs_of_blobs(p,ra,max)
772: Blobs *p;
773: RLE_Yrun *ra;
774: int max;
775: { int runs;
776: Blob *pp,**ppp;
777: runs = 0;
778: if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
779: runs += runs_of_blob(pp,ra+runs,max-runs);
780: return(runs);
781: }
782:
783: /* ascending lexicographic order on y,xs */
784: int local_rn_asc(r1,r2)
785: RLE_Yrun *r1,*r2;
786: { if(r1->y < r2->y) return(-1);
787: else if(r1->y==r2->y) {
788: if(r1->xs < r2->xs) return(-1);
789: else if (r1->xs == r2->xs) return(0);
790: else return(1);
791: }
792: else return(1);
793: }
794:
795: RLE_Lines *rle_lines_of_page(pgp)
796: Page *pgp;
797: { static RLE_Lines rls;
798: int no_runs,cy,ri;
799: RLE_Yrun *ra,*cr;
800: RLE_Run *lr;
801: RLE_Line *cl;
802: /* count runs */
803: no_runs = no_runs_of_page(pgp);
804: if(_O.dbg_r) err("no_runs %d",no_runs);
805: /* allocate runs array */
806: if((ra=(RLE_Yrun *)malloc(no_runs*sizeof(RLE_Yrun)))==NULL)
807: abort("rle_lines_of_page: can't malloc ra[%d]",no_runs);
808: runs_of_page(pgp,ra,no_runs);
809: /* sort runs ascending on (y,xs) */
810: qsort(ra,no_runs,sizeof(RLE_Yrun),local_rn_asc);
811: /* count RLE_lines.mny */
812: rls.mny = 0; cy=INT_MIN;
813: for(ri=0,cr=ra; ri<no_runs; ri++,cr++)
814: if(cr->y!=cy) {
815: rls.mny++;
816: cy = cr->y;
817: };
818: /* allocate RLE_lines */
819: if((rls.rla=(RLE_Line *)malloc(rls.mny*sizeof(RLE_Line)))==NULL)
820: abort("rle_lines_of_page: can't malloc rls.rla[%d]",rls.mny);
821: /* fill in RLE_lines */
822: cy=INT_MIN; cl=rls.rla-1;
823: for(ri=0,cr=ra; ri<no_runs; ri++,cr++) {
824: if(cr->y!=cy) {
825: cl++;
826: cl->y = cy = cr->y;
827: cl->runs = 0;
828: lr = cl->r;
829: };
830: lr->xs = cr->xs; lr->xe = cr->xe; lr++; cl->runs++;
831: };
832: free(ra);
833: return(&rls);
834: }
835:
836: Bbx *bbx_of_rle_lines(rlsp)
837: RLE_Lines *rlsp;
838: { static Bbx res;
839: Bbx r;
840: int li,ri;
841: RLE_Line *lp;
842: RLE_Run *rp;
843: res = empty_Bbx;
844: for(li=0,lp=rlsp->rla; li<rlsp->mny; li++,lp++) {
845: r.a.y = r.b.y = lp->y;
846: for(ri=0,rp=lp->r; ri<lp->runs; ri++,rp++) {
847: r.a.x = rp->xs;
848: r.b.x = rp->xe;
849: merge_bbx(&r,&res);
850: };
851: };
852: return(&res);
853: }
854:
855: translate_rle_lines(r,p)
856: RLE_Lines *r;
857: Sp p;
858: { int li,ri;
859: RLE_Line *lp;
860: RLE_Run *rp;
861: for(li=0,lp=r->rla; li<r->mny; li++,lp++) {
862: lp->y += p.y;
863: for(ri=0,rp=lp->r; ri<lp->runs; ri++,rp++) {
864: rp->xs += p.x;
865: rp->xe += p.x;
866: };
867: };
868: }
869:
870: RLE_Line *binary_source(a)
871: Copy_arg *a;
872: { static RLE_Line rl;
873: unsigned char *inline;
874: a->bop = F;
875: if(PIC_rline(a->ph,&inline)==1) {
876: rl.runs =
877: rlbr(inline,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r);
878: rl.y = a->ph->cy;
879: rl.len = a->wid;
880: if(_O.dbg_r) nerr_RLE_Line("binary_source: ",&rl);
881: return(&rl);
882: }
883: else { if(_O.dbg_r) nerr_RLE_Line("binary_source: ",NULL);
884: return(NULL);
885: };
886: }
887:
888: RLE_Line *bitmap_source(a)
889: Copy_arg *a;
890: { static RLE_Line rl;
891: unsigned char *inline;
892: register unsigned char *cp,*ep,*rb;
893: a->bop = F;
894: if(PIC_rline(a->ph,&inline)==1) {
895: /* reverse bit order in each byte */
896: rb=bm_consts.Rbits;
897: ep=(cp=inline)+a->ph->bpl;
898: while(cp<ep) { *cp = rb[*cp]; cp++; };
899: rl.runs =
900: rlbr(inline,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r);
901: rl.y = a->ph->cy;
902: rl.len = a->wid;
903: if(_O.dbg_r) nerr_RLE_Line("bitmap_source: ",&rl);
904: return(&rl);
905: }
906: else { if(_O.dbg_r) nerr_RLE_Line("binary_source: ",NULL);
907: return(NULL);
908: };
909: }
910:
911: RLE_Line *bitfile_source(a)
912: Copy_arg *a;
913: #define dbg_Bi (F)
914: { static RLE_Line rl;
915: unsigned char *cp,*ep,*pp;
916: int ch,ci;
917: a->bop = F;
918: /* copy current line to prior */
919: memcpy(a->ph->pline,a->ph->line,a->ph->bpl);
920: /* read one binary raster line */
921: ep=(cp=a->ph->line)+a->ph->bpl;
922: while(cp<ep) {
923: if((ch=getc(a->ph->fp))!=EOF) {
924: if(ch<127) {
925: if(dbg_Bi) err("cb: %o",ch);
926: if((fread(cp,1,2*ch,a->ph->fp))==2*ch) {
927: cp += 2*ch;
928: }
929: else return(NULL);
930: }
931: else { ch &= 0x7F;
932: if(dbg_Bi) err("cb: 0200+%o",ch);
933: if((fread(cp,1,2,a->ph->fp))==2) {
934: cp += 2;
935: for(ci=0;ci<ch-1;ci++,cp+=2) {
936: *cp = *(cp-2);
937: *(cp+1) = *(cp-1);
938: };
939: }
940: else return(NULL);
941: };
942: }
943: else return(NULL);
944: };
945: /* reverse bit-order, & xor with prior line */
946: for(ep=(cp=a->ph->line)+a->ph->bpl,pp=a->ph->pline; cp<ep; cp++,pp++) {
947: *cp = bm_consts.Rbits[*cp] ^ *pp;
948: if(dbg_Bi) err("db: %o = ?? ^ %o",*cp,*pp);
949: };
950: rl.runs =
951: rlbr(a->ph->line,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r);
952: rl.y = ++a->ph->cy;
953: rl.len = a->wid;
954: if(_O.dbg_r) nerr_RLE_Line("bitfile_source: ",&rl);
955: return(&rl);
956: }
957:
958: RLE_Line *dim_source(a)
959: Copy_arg *a;
960: { static RLE_Line *rlp,*rlq,rl;
961: if(a->bop) {
962: a->ph->cy = a->ph->bx.a.y-1;
963: rlq=(rlp=a->rles.rla)+a->rles.mny;
964: };
965: if(_O.dbg_r) {
966: err("dim_source: a->bop %d a->ph->cy %d",a->bop,a->ph->cy);
967: nerr_RLE_Line("*rlp",rlp);
968: };
969: a->bop = F;
970: a->ph->cy++;
971: if(rlp<rlq) {
972: if(a->ph->cy < rlp->y) {
973: rl.y = a->ph->cy;
974: rl.runs = 0;
975: rl.len = a->wid;
976: if(_O.dbg_r) nerr_RLE_Line("dim_source: ",&rl);
977: return(&rl);
978: }
979: else if(a->ph->cy == rlp->y) {
980: rlp->len = a->wid;
981: rlp++;
982: if(_O.dbg_r) nerr_RLE_Line("dim_source: ",rlp-1);
983: return(rlp-1);
984: }
985: else { while(rlp<rlq && a->ph->cy>rlp->y) rlp++;
986: if(rlp>=rlq) {
987: if(_O.dbg_r) nerr_RLE_Line("dim_source: NULL");
988: return(NULL);
989: }
990: else { rlp->len = a->wid;
991: rlp++;
992: if(_O.dbg_r) nerr_RLE_Line("dim_source: ",rlp-1);
993: return(rlp-1);
994: };
995: };
996: }
997: else { if(_O.dbg_r) nerr_RLE_Line("dim_source: NULL");
998: return(NULL);
999: };
1000: }
1001:
1002: RLE_Line *rle_source(a)
1003: Copy_arg *a;
1004: { static RLE_Line *rl;
1005: a->bop = F;
1006: if((rl=RLE_get_Line(a->ph->bx.a.x,a->ph->bx.b.x))!=NULL) {
1007: a->ph->cy = rl->y;
1008: rl->len = a->wid;
1009: if(_O.dbg_r) nerr_RLE_Line("rle_source: ",rl);
1010: return(rl);
1011: }
1012: else { if(_O.dbg_r) nerr_RLE_Line("rle_source: ",NULL);
1013: return(NULL);
1014: };
1015: }
1016:
1017: /* Read next line of runs from pic file, with runs shifted to lie in the range
1018: [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
1019: RLE_Line *pic_source(a)
1020: Copy_arg *a;
1021: { static RLE_Line rl;
1022: unsigned char *inline;
1023: a->bop = F;
1024: if(PIC_rline(a->ph,&inline)==1) {
1025: rl.runs = trcr(inline,
1026: 0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,
1027: a->thresh,rl.r);
1028: rl.y = a->ph->cy;
1029: rl.len = a->wid;
1030: if(_O.dbg_r) nerr_RLE_Line("pic_source: ",&rl);
1031: return(&rl);
1032: }
1033: else { if(_O.dbg_r) nerr_RLE_Line("pic_source: ",NULL);
1034: return(NULL);
1035: };
1036: }
1037:
1038: /* Read next line of runs from g31 file, with runs shifted to lie in the range
1039: [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
1040: RLE_Line *g31_source(a)
1041: Copy_arg *a;
1042: { static RLE_Line *rlp,rl;
1043: RLE_Run *rp,*ep,*np;
1044: if((rlp=g31_to_rlel(a->tbl,a->bf,a->bop))!=NULL) {
1045: a->bop = F;
1046: rlp->y = ++a->ph->cy;
1047: rlp->len = a->wid;
1048: if(a->ph->bx.a.x!=0) {
1049: /* must shift run indices */
1050: rl.y = rlp->y;
1051: rl.len = rlp->len;
1052: if((rl.runs=rlp->runs)>0) {
1053: for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) {
1054: np->xs = rp->xs + a->ph->bx.a.x;
1055: np->xe = rp->xe + a->ph->bx.a.x;
1056: };
1057: };
1058: if(_O.dbg_r) nerr_RLE_Line("g31_source: ",&rl);
1059: return(&rl);
1060: }
1061: else { if(_O.dbg_r) nerr_RLE_Line("g31_source: ",rlp);
1062: return(rlp);
1063: };
1064: }
1065: else { if(_O.dbg_r) nerr_RLE_Line("g31_source: ",NULL);
1066: return(NULL);
1067: };
1068: }
1069:
1070: /* Read next line of runs from g32 file, with runs shifted to lie in the range
1071: [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
1072: RLE_Line *g32_source(a)
1073: Copy_arg *a;
1074: { static RLE_Line *rlp,rl;
1075: RLE_Run *rp,*ep,*np;
1076: if((rlp=g32_to_rlel(a->tbl,a->bf,a->bop))!=NULL) {
1077: a->bop = F;
1078: rlp->y = ++a->ph->cy;
1079: rlp->len = a->wid;
1080: if(a->ph->bx.a.x!=0) {
1081: /* must shift run indices */
1082: if(_O.dbg_r) err("g32_source: shift +%d",a->ph->bx.a.x);
1083: rl.y = rlp->y;
1084: rl.len = rlp->len;
1085: if((rl.runs=rlp->runs)>0) {
1086: for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) {
1087: np->xs = rp->xs + a->ph->bx.a.x;
1088: np->xe = rp->xe + a->ph->bx.a.x;
1089: };
1090: };
1091: if(_O.dbg_r) nerr_RLE_Line("g32_source: ",&rl);
1092: return(&rl);
1093: }
1094: else { if(_O.dbg_r) nerr_RLE_Line("g32_source: ",rlp);
1095: return(rlp);
1096: };
1097: }
1098: else { if(_O.dbg_r) nerr_RLE_Line("g32_source: ",NULL);
1099: return(NULL);
1100: };
1101: }
1102:
1103: /* Read next line of runs from g4 file, after shifting runs to lie in the range
1104: [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
1105: RLE_Line *g4_source(a)
1106: Copy_arg *a;
1107: { static RLE_Line *rlp,rl;
1108: RLE_Run *rp,*ep,*np;
1109: if((rlp=g4_to_rlel(a->tbl,a->bf,a->bop,a->wid))!=NULL) {
1110: a->bop = F;
1111: rlp->y = ++a->ph->cy;
1112: rlp->len = a->wid;
1113: if(a->ph->bx.a.x!=0) { /* shift runs */
1114: rl.y = rlp->y;
1115: rl.len = rlp->len;
1116: if((rl.runs=rlp->runs)>0) {
1117: for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) {
1118: np->xs = rp->xs + a->ph->bx.a.x;
1119: np->xe = rp->xe + a->ph->bx.a.x;
1120: };
1121: };
1122: if(_O.dbg_r) nerr_RLE_Line("g4_source: ",&rl);
1123: return(&rl);
1124: }
1125: else { if(_O.dbg_r) nerr_RLE_Line("g4_source: ",rlp);
1126: return(rlp);
1127: };
1128: }
1129: else { a->bop = F;
1130: if(_O.dbg_r) nerr_RLE_Line("g4_source: ",NULL);
1131: return(NULL);
1132: };
1133: }
1134:
1135: binary_sink(rl,a)
1136: RLE_Line *rl;
1137: Copy_arg *a;
1138: { int stat;
1139: if(_O.dbg_r) nerr_RLE_Line("binary_sink: ",rl);
1140: if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; }
1141: if(rl!=NULL) {
1142: memset(a->ph->line,'\0',a->ph->bpl);
1143: if(rl->runs>0) {
1144: /* convert *rl to binary, using ``little-endian'' bit-order */
1145: brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
1146: };
1147: if((stat=PIC_wline(a->ph,a->ph->line))!=1)
1148: abort("binary_sink: can't write: stat %d",stat);
1149: };
1150: return(1);
1151: }
1152:
1153: bitmap_sink(rl,a)
1154: RLE_Line *rl;
1155: Copy_arg *a;
1156: { int stat;
1157: if(_O.dbg_r) nerr_RLE_Line("bitmap_sink: ",rl);
1158: if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; }
1159: if(rl!=NULL) {
1160: memset(a->ph->line,'\0',a->ph->bpl);
1161: if(rl->runs>0) {
1162: /* convert *rl to binary, using ``big-endian'' bit-order */
1163: brrlb(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
1164: };
1165: if((stat=PIC_wline(a->ph,a->ph->line))!=1)
1166: abort("bitmap_sink: can't write: stat %d",stat);
1167: };
1168: return(1);
1169: }
1170:
1171: /* Write bitfile(9.5) format */
1172: bitfile_sink(rl,a)
1173: RLE_Line *rl;
1174: Copy_arg *a;
1175: #define dbg_Bo (F)
1176: { int stat;
1177: int ci,towrite;
1178: register unsigned char uc,*cp,*pp,*ep;
1179: if(_O.dbg_r||dbg_Bo) nerr_RLE_Line("bitfile_sink: ",rl);
1180: if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; }
1181: if(rl!=NULL) {
1182: /* copy current to prior */
1183: memcpy(a->ph->pline,a->ph->line,a->ph->bpl);
1184: memset(a->ph->line,'\0',a->ph->bpl);
1185: if(rl->runs>0) {
1186: /* convert *rl to binary, using ``big-endian'' bit-order */
1187: brrlb(rl->runs,rl->r,
1188: a->ph->bx.a.x,a->ph->bx.b.x,
1189: 0,a->ph->line);
1190: if(dbg_Bo) {
1191: unsigned char *cb,*eb;
1192: fprintf(stderr,"a->ph->line: ");
1193: for(eb=(cb=a->ph->line)+a->ph->bpl;cb<eb;cb++)
1194: fprintf(stderr,"%02X",*cb);
1195: fprintf(stderr,"\n");
1196: };
1197: };
1198: /* break up output into blocks of 2*126 bytes;
1199: SHOULD also try run-length coding */
1200: ci=0; while((towrite=a->ph->bpl-ci) > 0) {
1201: if(towrite >= 2*127) towrite=2*126;
1202: /* write control byte for block */
1203: uc = towrite/2;
1204: if(dbg_Bo) err("cb: %02X",uc);
1205: putc(uc,a->ph->fp);
1206: for(ep=(cp=a->ph->line+ci)+towrite,pp=a->ph->pline+ci;
1207: cp<ep; cp++,pp++) {
1208: /* write XOR byte */
1209: uc = *cp ^ *pp;
1210: if(dbg_Bo) err("db %d: %02X = c%02X ^ p%02X",cp-a->ph->line,uc,*cp,*pp);
1211: putc(uc,a->ph->fp);
1212: };
1213: ci += towrite;
1214: };
1215: }
1216: else { free(a->ph->line); a->ph->line=NULL;
1217: free(a->ph->pline); a->ph->pline=NULL;
1218: fflush(a->ph->fp);
1219: };
1220: }
1221:
1222: rle_sink(rl,a)
1223: RLE_Line *rl;
1224: Copy_arg *a;
1225: { if(_O.dbg_r) nerr_RLE_Line("rle_sink: ",rl);
1226: if(a->bop) {
1227: RIC_hdr rh;
1228: rh.bx = a->ph->bx;
1229: rh.res_x = a->ph->res_x;
1230: rh.res_y = a->ph->res_y;
1231: RLE_put_hdr(fileno(a->ph->fp),&rh,1);
1232: a->ph->cy = a->ph->bx.a.y-1;
1233: a->bop=F;
1234: };
1235: if(rl!=NULL) {
1236: if(rl->runs>0) RLE_put_Line(fileno(a->ph->fp),rl);
1237: a->ph->cy++;
1238: }
1239: else RLE_close(fileno(a->ph->fp));
1240: return(1);
1241: }
1242:
1243: /* Write next line of runs to g31 file, after shifting runs to lie in the range
1244: [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */
1245: g31_sink(rl,a)
1246: RLE_Line *rl;
1247: Copy_arg *a;
1248: { int stat;
1249: RLE_Line crl;
1250: RLE_Run *rp,*ep,*np;
1251: if(_O.dbg_r) nerr_RLE_Line("g31_sink: ",rl);
1252: if(a->bop) {
1253: PIC_put_hdr(a->ph);
1254: /* treat FILE *a->ph->fp as a sequence of bits */
1255: if((a->bf=bopen(a->ph->fp,"w"))==NULL)
1256: abort("g31_sink: can't open bitfile");
1257: BOF_to_g31(a->bf);
1258: a->bop=F;
1259: };
1260: if(rl!=NULL) {
1261: /* check that rl->len is consistent with a->ph */
1262: if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) {
1263: err("g31_sink: rl->len %d != wid(a->ph.bx) %d",
1264: rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1);
1265: rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1;
1266: };
1267: if(rl->runs>0) {
1268: if(a->ph->bx.a.x!=0) { /* shift runs */
1269: crl.y = rl->y;
1270: crl.len = rl->len;
1271: crl.runs = rl->runs;
1272: for(ep=(rp=rl->r)+rl->runs,np=crl.r;
1273: rp<ep;
1274: rp++,np++) {
1275: np->xs = rp->xs - a->ph->bx.a.x;
1276: np->xe = rp->xe - a->ph->bx.a.x;
1277: };
1278: rlel_to_g31(&crl,crl.len,a->bf);
1279: }
1280: else rlel_to_g31(rl,rl->len,a->bf);
1281: }
1282: else rlel_to_g31(NULL,rl->len,a->bf);
1283: a->ph->cy++;
1284: }
1285: else { EOF_to_g31(a->bf);
1286: bclose(a->bf);
1287: };
1288: return(1);
1289: }
1290:
1291: /* Write next line of runs to g32 file, after shifting runs to lie in the range
1292: [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */
1293: g32_sink(rl,a)
1294: RLE_Line *rl;
1295: Copy_arg *a;
1296: { static RLE_Line prl;
1297: RLE_Line *pl;
1298: RLE_Line crl;
1299: RLE_Run *rp,*ep,*np;
1300: if(_O.dbg_r) nerr_RLE_Line("g32_sink: ",rl);
1301: if(a->bop) {
1302: PIC_put_hdr(a->ph);
1303: /* treat FILE *a->ph->fp as a sequence of bits */
1304: if((a->bf=bopen(a->ph->fp,"w"))==NULL)
1305: abort("can't open bitfile");
1306: BOF_to_g32(a->bf);
1307: a->bop=F;
1308: prl.runs = 0;
1309: };
1310: if(rl!=NULL) {
1311: /* check that rl->len is consistent with a->ph */
1312: if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) {
1313: err("g32_sink: rl->len %d != wid(a->ph.bx) %d",
1314: rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1);
1315: rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1;
1316: };
1317: prl.len = rl->len;
1318: prl.y = rl->y - 1;
1319: if(((a->ph->cy+1-a->ph->bx.a.y)%a->k)==0) pl=NULL; else pl=&prl;
1320: if(rl->runs>0) {
1321: if(a->ph->bx.a.x!=0) { /* shift runs */
1322: crl.y = rl->y;
1323: crl.len = rl->len;
1324: crl.runs = rl->runs;
1325: for(ep=(rp=rl->r)+rl->runs,np=crl.r;
1326: rp<ep;
1327: rp++,np++) {
1328: np->xs = rp->xs - a->ph->bx.a.x;
1329: np->xe = rp->xe - a->ph->bx.a.x;
1330: };
1331: rlel_to_g32(pl,&crl,crl.len,a->bf);
1332: prl.y=crl.y;
1333: prl.len=crl.len;
1334: prl.runs=crl.runs;
1335: memcpy(prl.r,crl.r,2*prl.runs*sizeof(short));
1336: }
1337: else { rlel_to_g32(pl,rl,rl->len,a->bf);
1338: prl.y=rl->y;
1339: prl.len=rl->len;
1340: prl.runs=rl->runs;
1341: memcpy(prl.r,rl->r,2*prl.runs*sizeof(short));
1342: };
1343: }
1344: else { rlel_to_g32(pl,NULL,rl->len,a->bf);
1345: prl.y=rl->y;
1346: prl.len=rl->len;
1347: prl.runs=0;
1348: }
1349: a->ph->cy++;
1350: }
1351: else { EOF_to_g32(a->bf);
1352: bclose(a->bf);
1353: prl.runs = 0;
1354: };
1355: return(1);
1356: }
1357:
1358: /* Write next line of runs to g4 file, after shifting runs to lie in the range
1359: [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */
1360: g4_sink(rl,a)
1361: RLE_Line *rl;
1362: Copy_arg *a;
1363: { static RLE_Line prl;
1364: RLE_Line crl;
1365: RLE_Run *rp,*ep,*np;
1366: if(_O.dbg_r) nerr_RLE_Line("g4_sink: ",rl);
1367: if(a->bop) {
1368: PIC_put_hdr(a->ph);
1369: /* treat FILE *a->ph->fp as a sequence of bits */
1370: if((a->bf=bopen(a->ph->fp,"w"))==NULL)
1371: abort("can't open bitfile");
1372: BOF_to_g4(a->bf);
1373: a->bop=F;
1374: prl.runs = 0;
1375: };
1376: if(rl!=NULL) {
1377: /* check that rl->len is consistent with a->ph */
1378: if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) {
1379: err("g4_sink: rl->len %d != wid(a->ph.bx) %d",
1380: rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1);
1381: rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1;
1382: };
1383: if(rl->runs>0) {
1384: if(a->ph->bx.a.x!=0) { /* shift runs */
1385: crl.y = rl->y;
1386: crl.len = rl->len;
1387: crl.runs = rl->runs;
1388: for(ep=(rp=rl->r)+rl->runs,np=crl.r;
1389: rp<ep;
1390: rp++,np++) {
1391: np->xs = rp->xs - a->ph->bx.a.x;
1392: np->xe = rp->xe - a->ph->bx.a.x;
1393: };
1394: rlel_to_g4(&prl,&crl,crl.len,a->bf);
1395: prl.y=crl.y;
1396: prl.len=crl.len;
1397: prl.runs=crl.runs;
1398: memcpy(prl.r,crl.r,2*prl.runs*sizeof(short));
1399: }
1400: else { rlel_to_g4(&prl,rl,rl->len,a->bf);
1401: prl.y=rl->y;
1402: prl.len=rl->len;
1403: prl.runs=rl->runs;
1404: memcpy(prl.r,rl->r,2*prl.runs*sizeof(short));
1405: };
1406: }
1407: else { rlel_to_g4(&prl,NULL,rl->len,a->bf);
1408: prl.runs=0;
1409: }
1410: a->ph->cy++;
1411: }
1412: else { EOF_to_g4(a->bf);
1413: bclose(a->bf);
1414: prl.runs = 0;
1415: };
1416: return(1);
1417: }
1418:
1419: pic_sink(rl,a)
1420: RLE_Line *rl;
1421: Copy_arg *a;
1422: { int stat;
1423: if(_O.dbg_r) nerr_RLE_Line("pic_sink: ",rl);
1424: if(a->bop) {
1425: PIC_put_hdr(a->ph);
1426: a->bop=F;
1427: };
1428: if(rl!=NULL) {
1429: crrl(rl->runs,rl->r,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->line);
1430: if((stat=PIC_wline(a->ph,a->ph->line))!=1)
1431: abort("pic_sink: can't write: stat %d",stat);
1432: };
1433: return(1);
1434: }
1435:
1436: #if CPU==SUN
1437: post_sink(rl,a)
1438: RLE_Line *rl;
1439: Copy_arg *a;
1440: { int stat;
1441: if(_O.dbg_r) nerr_RLE_Line("post_sink: ",rl);
1442: if (a->bop) {
1443: PIC_put_hdr(a->ph); /* needed for allocation of h->line? */
1444: POST_start(a->ph);
1445: a->bop = F;
1446: };
1447: if(rl!=NULL) {
1448: memset(a->ph->line,'\0',a->ph->bpl);
1449: if(rl->runs>0) {
1450: /* convert *rl to binary, using ``little-endian'' bit-order */
1451: brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
1452: };
1453: if((stat=POST_wline(a->ph,a->ph->line))!=1)
1454: abort("post_sink: can't write: stat %d",stat);
1455: }
1456: else { POST_end();
1457: };
1458: return(1);
1459: }
1460: #else
1461: post_sink() {abort("-P postscript output unimplemented");};
1462: #endif
1463:
1464: #if CPU==SUN
1465: rast_sink(rl,a)
1466: RLE_Line *rl;
1467: Copy_arg *a;
1468: { int stat;
1469: if(_O.dbg_r) nerr_RLE_Line("rast_sink: ",rl);
1470: if (a->bop) {
1471: PIC_put_hdr(a->ph); /* needed for allocation of h->line? */
1472: RAST_start(a->ph);
1473: a->bop = F;
1474: };
1475: if(rl!=NULL) {
1476: memset(a->ph->line,'\0',a->ph->bpl);
1477: if(rl->runs>0) {
1478: /* convert *rl to binary, using ``little-endian'' bit-order */
1479: brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
1480: };
1481: if((stat=RAST_wline(a->ph,a->ph->line))!=1)
1482: abort("rast_sink: can't write: stat %d",stat);
1483: }
1484: else { RAST_end();
1485: };
1486: return(1);
1487: }
1488: #else
1489: rast_sink() {abort("-S sunraster output unimplemented");};
1490: #endif
1491:
1492: /* Save RLE_Line *rl in buffer, as packed binary, using ``little-endian''
1493: bit-packing order, rounding each line to the nearest int for speed.
1494: If a->bop, malloc a complete, contiguous buffer holding the entire page,
1495: and initialize its contents to zeroes.
1496: On each call with rl!=NULL, convert the given line to binary & save in buffer.
1497: When called with rl==NULL but a!=NULL, signalling end-of-page, do nothing.
1498: Normally, return kludgey (unsigned int *)1, like other sink functions.
1499: When called with rl==NULL && a==NULL, return pointer to buffer.
1500: It is the responsibility of the calling code to free the buffer. */
1501: unsigned int *binary_buffer(rl,a)
1502: RLE_Line *rl;
1503: Copy_arg *a;
1504: { static unsigned int *buf = NULL;
1505: static int ipl = 0; /* ints/line */
1506: int bufsz; /* (bytes) */
1507: unsigned int *result;
1508: #define BITS_PER_INT (8*sizeof(int))
1509: if(a!=NULL && a->bop) {
1510: /* round up to int boundary */
1511: ipl = (bbx_wid(&(a->ph->bx))+BITS_PER_INT-1)/BITS_PER_INT;
1512: bufsz = sizeof(int)*ipl*bbx_hgt(&(a->ph->bx));
1513: if((buf=(unsigned int *)malloc(bufsz))==NULL)
1514: abort("binary_buffer: can't alloc int buf[%d]",bufsz/sizeof(int));
1515: memset(buf,'\0',bufsz);
1516: a->bop=F;
1517: };
1518: if(rl!=NULL) {
1519: /* convert *rl to binary, using ``little-endian'' bit-order */
1520: if(rl->runs>0) {
1521: /* *rl --> binary, with ``little-endian'' bit-order */
1522: #if BIG_ENDIAN
1523: brrlb( rl->runs, rl->r, a->ph->bx.a.x, a->ph->bx.b.x,
1524: 0, buf+(ipl*(rl->y-a->ph->bx.a.y)) );
1525: #else
1526: brrl( rl->runs, rl->r, a->ph->bx.a.x, a->ph->bx.b.x,
1527: 0, buf+(ipl*(rl->y-a->ph->bx.a.y)) );
1528: #endif
1529: };
1530: return((unsigned int *)1);
1531: }
1532: else { if(a!=NULL) return((unsigned int *)1);
1533: else { result = buf;
1534: buf = NULL; ipl = 0;
1535: return(result);
1536: };
1537: };
1538: }
1539:
1540: /* Rotate binary buffer *buf (whose shape is specified by a->ph->bx),
1541: through angle tra->rot, and write the resulting stream of RLE_Line's to
1542: sink() one at a time, along with a rotated version of *a as the 2nd argument.
1543: Only PI/2 is supported; UNDER DEVELOPMENT: other multiples of PI/2 and
1544: small arbitrary angles. */
1545: rotate_binary_buffer(buf,tra,sink,a)
1546: unsigned int *buf;
1547: Transform_rlel_arg *tra;
1548: int (*sink)(); /* takes args: (RLE_Line *), and int */
1549: Copy_arg *a;
1550: { register int ipl; /* ints/line in binary buffer */
1551: Copy_arg ra; /* rotated */
1552: RLE_Line rl;
1553: #define TINY_ANG (PI/1000)
1554: /* round up to int boundary */
1555: ipl = (bbx_wid(&(a->ph->bx))+BITS_PER_INT-1)/BITS_PER_INT;
1556: ra = *a;
1557: ra.bop=T;
1558: if((ra.ph = (PIC_hdr *)malloc(sizeof(PIC_hdr)))==NULL)
1559: abort("rotate_binary_buffer: can't malloc ra.ph");
1560: *(ra.ph) = *(a->ph);
1561: /* by arbitrary convention, rotated bx.a will coincide with input bx.a */
1562: if(tra->rot <= PI/2+TINY_ANG && tra->rot >= PI/2-TINY_ANG) {
1563: int ey,ii;
1564: register RLE_Run *rp;
1565: register unsigned int *cb,*eb,bm,obm;
1566: register short rx;
1567: ra.ph->bx.b.x = a->ph->bx.a.x + bbx_hgt(&(a->ph->bx)) - 1;
1568: ra.ph->bx.b.y = a->ph->bx.a.y + bbx_wid(&(a->ph->bx)) - 1;
1569: rl.len = ra.wid = bbx_wid(&(ra.ph->bx));
1570: rl.y = ra.ph->bx.a.y; ey=ra.ph->bx.b.y;
1571: ii=0; bm=01;
1572: do { obm=0; /* assume 0 left of margin */
1573: rp=rl.r-1;
1574: rx=ra.ph->bx.a.x;
1575: cb=(eb=buf+ii)+((rl.len-1)*ipl);
1576: do { if((*cb & bm)!=obm) {
1577: if(obm) { rp->xe=rx-1; obm=0; }
1578: else { (++rp)->xs=rx; obm=bm; };
1579: };
1580: rx++;
1581: }
1582: while( (cb -= ipl) >= eb );
1583: if(obm) rp->xe=rx-1;
1584: rl.runs = rp - rl.r + 1;
1585: sink(&rl,&ra);
1586: if((bm<<=1)==0) {ii++; bm=01;};
1587: }
1588: while((++rl.y)<=ey);
1589: }
1590: else if(tra->rot <= PI+TINY_ANG && tra->rot >= PI-TINY_ANG) {
1591: rl.len = ra.wid;
1592: abort("rotate_binary_buffer: tra->rot==%g deg unimplemented",
1593: tra->rot/DtoR);
1594: }
1595: else if(tra->rot <= 3*PI/2+TINY_ANG && tra->rot >= 3*PI/2-TINY_ANG) {
1596: ra.ph->bx.b.x = a->ph->bx.a.x + bbx_hgt(&(a->ph->bx)) - 1;
1597: ra.ph->bx.b.y = a->ph->bx.a.y + bbx_wid(&(a->ph->bx)) - 1;
1598: rl.len = ra.wid = bbx_wid(&(ra.ph->bx));
1599: abort("rotate_binary_buffer: tra->rot==%g deg unimplemented",
1600: tra->rot/DtoR);
1601: }
1602: else if(tra->rot <= 20.0*DtoR && tra->rot >= -20.0*DtoR) {
1603: /* rotation by ``small'' angle */
1604: Sp ce; /* center of image to be rotated */
1605: double rcos,rsin; /* real rotation vector (cos,sin) */
1606: double irx,iry; /* current rotated pixel location */
1607: register int sx,sy,ex,ey,rx,ry;
1608: register RLE_Run *rp;
1609: register int pel,opel;
1610: register int orx,ory;
1611: if(0) err("rotate_binary_buffer: tra->rot==%g deg under development",
1612: tra->rot/DtoR);
1613: /* conventionally, keep the same window as the input image,
1614: while rotating about its midpoint */
1615: rl.len = ra.wid = bbx_wid(&(ra.ph->bx));
1616: sx = ra.ph->bx.a.x; ex = ra.ph->bx.b.x;
1617: sy = ra.ph->bx.a.y; ey = ra.ph->bx.b.y;
1618: ce.x = sx + bbx_wid(&(ra.ph->bx))/2;
1619: ce.y = sy + bbx_hgt(&(ra.ph->bx))/2;
1620: rcos = cos(tra->rot); rsin = sin(tra->rot);
1621: for(ory=sy; ory<=ey; ory++) {
1622: opel=0; /* left of output margin: assume pel==0 */
1623: rp=rl.r-1;
1624: irx = ((rcos*(sx - ce.x) - rsin*(ory - ce.y))) + ce.x;
1625: iry = ((rsin*(sx - ce.x) + rcos*(ory - ce.y))) + ce.y;
1626: for(orx=sx; orx<=ex; orx++) {
1627: rx = (int)(irx + 0.5); ry = (int)(iry + 0.5);
1628: if(rx<sx || rx>ex || ry<sy || ry>ey)
1629: /* outside input image: assume pel==0 */
1630: pel=0;
1631: else /* look at bit within input image */ {
1632: int ix,iy,bx;
1633: iy = (ry-sy)*ipl;
1634: ix = rx/BITS_PER_INT;
1635: bx = rx%BITS_PER_INT;
1636: #if BIG_ENDIAN
1637: pel = (buf[ iy + ix ] & (01<<(BITS_PER_INT-bx-1))) ? 1 : 0;
1638: #else
1639: pel = (buf[ iy + ix ] & (01<<bx)) ? 1 : 0;
1640: #endif
1641: };
1642: if(pel!=opel) {
1643: if(opel) { rp->xe=orx-1; opel=0; }
1644: else { (++rp)->xs=orx; opel=pel; };
1645: };
1646: /* step one pel to the right in output image */
1647: irx += rcos; iry += rsin;
1648: };
1649: if(opel) rp->xe=orx-1;
1650: rl.runs = rp - rl.r + 1;
1651: rl.y = ory;
1652: sink(&rl,&ra);
1653: };
1654: }
1655: else { abort("rotate_binary_buffer: tra->rot==%g deg unimplemented",
1656: tra->rot/DtoR);
1657: };
1658: sink(NULL,&ra); /* signal end-of-page */
1659: }
1660:
1661: /* Copy a source of RLE_Lines to a sink of RLE_Lines, transforming them
1662: by trimming, shifting, scaling, truncation, and rotation.
1663: The source is function ir(), which returns non-empty lines only,
1664: or NULL on end of page. It is passed `bop=T' on beginning of page.
1665: On return from ir(), ia->ph->cy holds the index of the line, whose height is
1666: guaranteed to lie in the range [ia->ph->bx.a.y,ia->ph->bx.b.y].
1667: All input runs are guaranteed to lie in [ia->ph->bx.a.x,ia->ph->bx.b.x].
1668: The maximum length (in pels) of each source line is ia->wid.
1669: The sink function or() takes two arguments:
1670: RLE_Line *rl; ==NULL on end-of-page
1671: Copy_arg *a;
1672: The lines sent to the sink must be in unbroken ascending integer
1673: sequence of rl->y (thus blank lines must be explicitly sent). At all times,
1674: oa->ph->cy is the line last written. After the first call to or(),
1675: oa->ph->cy lies in the range [oa->ph->bx.a.y,oa->ph->bx.b.y].
1676: Trimming, shifting, scaling, and truncation are performed either
1677: here or in function transform_rlel(). Rotation is handled specially:
1678: the complete output image (after all other transformations have been
1679: performed) is saved in an intermediate buffer (as packed binary), then
1680: rotated. Rotation is much slower than the other operations, mainly due
1681: to the necessity of touching every pixel. (Manhattan rotations might be
1682: faster if the buffer held RLE_lines, but then it would be next-to-impossible
1683: to extend to arbitrary rotations someday.)
1684: */
1685: transform_rlels(ir,ia,or,oa,tra)
1686: RLE_Line *(*ir)(); /* return next RLE_Line */
1687: Copy_arg *ia; /* used here (bop & wid) & passed to ir() */
1688: int (*or)(); /* write next RLE_Line */
1689: Copy_arg *oa; /* used here (bop && ph->bx.*.y) & passed to or() */
1690: Transform_rlel_arg *tra;
1691: { RLE_Line *irl,*orl;
1692: static RLE_Line rl0 = Init_RLE_Line; /* empty line */
1693: int tr_y; /* transformed y */
1694: int (*sv_or)();
1695: if(tra->rot!=0.0) {
1696: /* if must rotate the image, first buffer the entire
1697: set of output RLE_Lines */
1698: sv_or = or;
1699: or = (int (*)())binary_buffer;
1700: };
1701: /* signal beginning of page; reset in source() & sink() functions */
1702: ia->bop=oa->bop=T;
1703: /* set first output line number to write */
1704: tra->dy = (tra->sy = oa->ph->bx.a.y);
1705: while((irl=ir(ia))!=NULL) {
1706: if(F&&_O.dbg_r) nerr_RLE_Line("trans.i: ",irl);
1707: /* trim input lines' Y */
1708: if(irl->y < tra->tr.a.y) continue;
1709: if(irl->y > tra->tr.b.y) break;
1710: /* compute the output Y that is equal to the last
1711: of the group of transformed equivalent Y's */
1712: tr_y = (int)((irl->y + tra->off.y + 1)*tra->scl.y) - 1;
1713: /* truncate if necessary */
1714: if(tr_y>oa->ph->bx.b.y) tr_y = oa->ph->bx.b.y;
1715: /* supply implicit blank line(s) of the same length */
1716: while(tra->sy < tr_y) {
1717: rl0.len = ia->wid;
1718: transform_rlel(&rl0,tra,or,oa);
1719: };
1720: irl->len = ia->wid;
1721: transform_rlel(irl,tra,or,oa);
1722: };
1723: /* supply terminating blank line(s) of the same length */
1724: while(tra->sy < oa->ph->bx.b.y) {
1725: rl0.len = ia->wid;
1726: transform_rlel(&rl0,tra,or,oa);
1727: };
1728: transform_rlel(NULL,tra,or,oa); /* signal end of page */
1729: /* read input until end of page occurs; this is required
1730: to support catenated pages */
1731: while(irl!=NULL) irl=ir(ia);
1732: if(tra->rot!=0.0) {
1733: unsigned int *buf;
1734: buf = binary_buffer(NULL,NULL);
1735: if(buf!=NULL) {
1736: rotate_binary_buffer(buf,tra,sv_or,oa);
1737: free(buf);
1738: };
1739: };
1740: }
1741:
1742: process_page(i,o)
1743: Copy_arg *i,*o;
1744: { RLE_Line *(*source)();
1745: int (*sink)();
1746: char unit,*up,cpy[40]; /* units character */
1747: Transform_rlel_arg tra;
1748:
1749: i->wid = bbx_wid(&(i->ph->bx));
1750:
1751: _O.trim = max_Bbx; /* start by trimming nothing */
1752: /* translate units in option arguments */
1753: if(_O.optarg_l!=NULL) {
1754: strcpy(cpy,_O.optarg_l);
1755: if((up=strpbrk(cpy,UNITS))!=NULL) {
1756: unit= *up; *up='\0';
1757: _O.trim.a.x=vto_scoor(atof(cpy),unit,i->ph->res_x);
1758: }
1759: else /* assume scanner coordinates */
1760: _O.trim.a.x=atoi(cpy);
1761: };
1762: if(_O.optarg_r!=NULL) {
1763: strcpy(cpy,_O.optarg_r);
1764: if((up=strpbrk(cpy,UNITS))!=NULL) {
1765: unit= *up; *up='\0';
1766: _O.trim.b.x=vto_scoor(atof(cpy),unit,i->ph->res_x);
1767: }
1768: else /* assume scanner coordinates */
1769: _O.trim.b.x=atoi(cpy);
1770: _O.trim.b.x--; /* -w coordinate is open, Bbx is closed */
1771: };
1772: if(_O.optarg_t!=NULL) {
1773: strcpy(cpy,_O.optarg_t);
1774: if((up=strpbrk(cpy,UNITS))!=NULL) {
1775: unit= *up; *up='\0';
1776: _O.trim.a.y=vto_scoor(atof(cpy),unit,i->ph->res_y);
1777: }
1778: else /* assume scanner coordinates */
1779: _O.trim.a.y=atoi(cpy);
1780: };
1781: if(_O.optarg_b!=NULL) {
1782: strcpy(cpy,_O.optarg_b);
1783: if((up=strpbrk(cpy,UNITS))!=NULL) {
1784: unit= *up; *up='\0';
1785: _O.trim.b.y=vto_scoor(atof(cpy),unit,i->ph->res_y);
1786: }
1787: else /* assume scanner coordinates */
1788: _O.trim.b.y=atoi(cpy);
1789: _O.trim.b.y--; /* -w coordinate is open, Bbx is closed */
1790: };
1791: /* Modified output margins may lie OUTSIDE the input window as well
1792: as within it. */
1793: if(_O.trim.a.x==Scoor_MIN) _O.trim.a.x=i->ph->bx.a.x;
1794: if(_O.trim.b.x==Scoor_MAX) _O.trim.b.x=i->ph->bx.b.x;
1795: if(_O.trim.a.y==Scoor_MIN) _O.trim.a.y=i->ph->bx.a.y;
1796: if(_O.trim.b.y==Scoor_MAX) _O.trim.b.y=i->ph->bx.b.y;
1797: if(_O.dbg_m) err("trim: %s",bbx_toa(&(_O.trim)));
1798:
1799: if(strcmp(i->ph->type,"binary")==0) { source = binary_source; }
1800: else if(strcmp(i->ph->type,"bitmap")==0) { source = bitmap_source; }
1801: else if(strcmp(i->ph->type,"bitfile")==0) { source = bitfile_source; }
1802: else if(strcmp(i->ph->type,"document-image")==0) { source = dim_source; }
1803: else if(strcmp(i->ph->type,"dim")==0) { source = dim_source; }
1804: else if(strcmp(i->ph->type,"rle")==0) {
1805: RIC_hdr rh;
1806: /* reopen RLE file to use system I/O (awkward, obsolescent) */
1807: lseek(fileno(i->ph->fp),0L,0);
1808: RLE_open(fileno(i->ph->fp),&rh);
1809: i->ph->cy = i->ph->bx.a.y-1;
1810: source = rle_source;
1811: }
1812: else if(strcmp(i->ph->type,"pico")==0
1813: ||strcmp(i->ph->type,"dump")==0) {
1814: i->thresh = _O.thresh;
1815: source = pic_source;
1816: }
1817: else if(strcmp(i->ph->type,"ccitt-g31")==0) {
1818: if((i->bf=bopen(i->ph->fp,"r"))==NULL)
1819: abort("can't open bitfile");
1820: i->tbl = ccitt_table();
1821: source = g31_source;
1822: }
1823: else if(strcmp(i->ph->type,"ccitt-g32")==0) {
1824: if((i->bf=bopen(i->ph->fp,"r"))==NULL)
1825: abort("can't open bitfile");
1826: i->tbl = ccitt_table();
1827: source = g32_source;
1828: }
1829: else if(strcmp(i->ph->type,"ccitt-g4")==0) {
1830: if((i->bf=bopen(i->ph->fp,"r"))==NULL)
1831: abort("can't open bitfile");
1832: i->tbl = ccitt_table();
1833: source = g4_source;
1834: }
1835: else if(strcmp(i->ph->type,"cdf-mrlc")==0) { source = cdf_mrlc_source; }
1836: else abort("Input file TYPE=%s unsupported",i->ph->type);
1837:
1838: if(_O.dbg_h) err("In %s",PIC_hdr_toa(i->ph));
1839:
1840: /* Adjudicate -R and -x options */
1841: if(_O.out_res.x==-2) {
1842: /* -R= specified: force resolutions to be equal to the greater */
1843: if(i->ph->res_x < i->ph->res_y) {
1844: _O.out_res.x = _O.out_res.y = i->ph->res_y;
1845: }
1846: else if(i->ph->res_y < i->ph->res_x) {
1847: _O.out_res.x = _O.out_res.y = i->ph->res_x;
1848: }
1849: else _O.out_res.x = _O.out_res.y = i->ph->res_x;
1850: };
1851: if(_O.out_res.x!=-1) { /* -Rx specified; override -xX */
1852: _O.expand.x = ((double)_O.out_res.x)/i->ph->res_x;
1853: if(_O.dbg_R && _O.expand.x!=1.0)
1854: err("horizontal resolution changed: x%g (%d -> %d)",
1855: _O.expand.x,i->ph->res_x,_O.out_res.x);
1856: };
1857: if(_O.out_res.y!=-1) { /* -R,y specified; override -x,Y */
1858: _O.expand.y = ((double)_O.out_res.y)/i->ph->res_y;
1859: if(_O.dbg_R && _O.expand.y!=1.0)
1860: err("vertical resolution changed: x%g (%d -> %d)",
1861: _O.expand.y,i->ph->res_y,_O.out_res.y);
1862: };
1863:
1864: /* Setup image transformation parameters */
1865: tra = empty_Transform_rlel_arg;
1866: tra.tr = _O.trim;
1867: tra.off = _O.offset;
1868: tra.scl = _O.expand;
1869: tra.wh.x = bbx_wid(&(tra.tr));
1870: tra.wh.y = bbx_hgt(&(tra.tr));
1871: tra.rev = _O.reverse;
1872: if(tra.scl.x!=1.0) {
1873: tra.wh.x = (int)(tra.wh.x*tra.scl.x+0.5);
1874: };
1875: if(tra.scl.y!=1.0) {
1876: tra.wh.y = (int)(tra.wh.y*tra.scl.y+0.5);
1877: };
1878: switch(_O.top) {
1879: case 't': /* default */ break;
1880: case 'l': /* top is really at left */
1881: tra.rot = (Radians)(PI/2);
1882: break;
1883: case 'b': /* top is really at bottom */
1884: tra.rot = (Radians)(PI);
1885: break;
1886: case 'r': /* top is really at right */
1887: tra.rot = (Radians)((3*PI)/2);
1888: break;
1889: case 'a': /* rotation angle given */
1890: tra.rot = _O.top_angle;
1891: break;
1892: };
1893: /* is the transform the identity? (speed-optimized special case) */
1894: tra.ident = ( (bbx_eq(&(tra.tr),&(i->ph->bx)))
1895: && (tra.scl.x==1.0)
1896: && (tra.scl.y==1.0)
1897: && (tra.off.x==0)
1898: && (tra.off.y==0)
1899: && (tra.rot==0.0) );
1900:
1901: /* compute transformed output box & resolution;
1902: don't rotate here (see transform_rlels()) */
1903: if(tra.ident) {
1904: o->ph->bx = i->ph->bx;
1905: o->ph->res_x = i->ph->res_x;
1906: o->ph->res_y = i->ph->res_y;
1907: }
1908: else { o->ph->bx = tra.tr;
1909: o->ph->bx.a.x += tra.off.x;
1910: o->ph->bx.b.x += tra.off.x;
1911: o->ph->bx.a.y += tra.off.y;
1912: o->ph->bx.b.y += tra.off.y;
1913: if(tra.scl.x!=1.0) {
1914: o->ph->bx.a.x = tra.scl.x*o->ph->bx.a.x;
1915: o->ph->bx.b.x = o->ph->bx.a.x + tra.wh.x-1;
1916: };
1917: if(tra.scl.y!=1.0) {
1918: o->ph->bx.a.y = tra.scl.y*o->ph->bx.a.y;
1919: o->ph->bx.b.y = o->ph->bx.a.y + tra.wh.y-1;
1920: };
1921: o->ph->res_x = (i->ph->res_x*tra.scl.x + 0.5);
1922: o->ph->res_y = (i->ph->res_y*tra.scl.y + 0.5);
1923: };
1924:
1925: if(_O.to_bin)
1926: { strcpy(o->ph->type,"binary"); sink = binary_sink; }
1927: else if(_O.to_bitfile)
1928: { strcpy(o->ph->type,"bitfile"); sink = bitfile_sink; }
1929: else if(_O.to_bitmap)
1930: { strcpy(o->ph->type,"bitmap"); sink = bitmap_sink; }
1931: else if (_O.to_rle) {
1932: if(strcmp(i->ph->type,"rle")==0)
1933: abort("can't both read and write TYPE=rle - sorry");
1934: strcpy(o->ph->type,"rle"); sink = rle_sink;
1935: }
1936: else if(_O.to_g31) { strcpy(o->ph->type,"ccitt-g31"); sink = g31_sink; }
1937: else if(_O.to_g32) {
1938: strcpy(o->ph->type,"ccitt-g32");
1939: o->k = _O.g32_k;
1940: sink = g32_sink;
1941: }
1942: else if(_O.to_g4) { strcpy(o->ph->type,"ccitt-g4"); sink = g4_sink; }
1943: else if(_O.to_pic) { strcpy(o->ph->type,"dump"); sink = pic_sink; }
1944: #if CPU==SUN
1945: else if(_O.to_post) { strcpy(o->ph->type,"postscript"); sink = post_sink; }
1946: #endif
1947: #if CPU==SUN
1948: else if(_O.to_rast) { strcpy(o->ph->type,"sunraster"); sink = rast_sink; }
1949: #endif
1950: if(i->ph->misc!=NULL) {
1951: o->ph->misc = i->ph->misc;
1952: i->ph->misc = NULL;
1953: };
1954: if(_O.dbg_h) err("Out %s",PIC_hdr_toa(o->ph));
1955:
1956: transform_rlels(source,i,sink,o,&tra);
1957:
1958: /* Synchronize filedes pointer with stream pointer */
1959: lseek(fileno(o->ph->fp),o->ph->seek = ftell(o->ph->fp),0);
1960: }
1961:
1962: /* A file may be a catenation of pages. */
1963: process_fps(i,o)
1964: FILE *i,*o;
1965: { Copy_arg ia,oa;
1966: int stat;
1967: ia = oa = empty_Copy_arg;
1968: ia.ph = alloc_PIC_hdr(i);
1969: oa.ph = alloc_PIC_hdr(o);
1970:
1971: stat=PIC_get_hdr(ia.ph);
1972: if(_O.dbg_h && stat!=1) err("PIC_get_hdr() returns status %d",stat);
1973:
1974: /* enforce bitfile(9) I/O restrictions */
1975: if(_O.from_bitfile && strcmp(ia.ph->type,"bitfile")!=0)
1976: abort("-Bi requires input to be bitfile(9.5) format");
1977: if(!_O.from_bitfile && strcmp(ia.ph->type,"bitfile")==0) {
1978: /* TYPE= is missing, erroneously: refuse to recognize it */
1979: abort("TYPE=... header is missing");
1980: };
1981:
1982: if(strcmp(ia.ph->type,"document-image")==0
1983: || strcmp(ia.ph->type,"dim")==0) {
1984: Page pg;
1985: skip_doc(i);
1986: if(frdb_page_etc(i,&pg,IsALL)==1) {
1987: ia.ph->bx = pg.bx;
1988: ia.ph->res_x = pg.res_x;
1989: ia.ph->res_y = pg.res_y;
1990: ia.rles = *rle_lines_of_page(&pg);
1991: if(_O.shrinkwrap!=-1) {
1992: Sp trans;
1993: ia.ph->bx = *bbx_of_rle_lines(&ia.rles);
1994: ia.ph->bx.a.x -= _O.shrinkwrap;
1995: ia.ph->bx.a.y -= _O.shrinkwrap;
1996: ia.ph->bx.b.x += _O.shrinkwrap;
1997: ia.ph->bx.b.y += _O.shrinkwrap;
1998: if(bbx_area(&(ia.ph->bx))<=0)
1999: abort("-W%d shrinks to nothing",_O.shrinkwrap);
2000: trans.x = -ia.ph->bx.a.x; trans.y = -ia.ph->bx.a.y;
2001: translate_rle_lines(&ia.rles,trans);
2002: ia.ph->bx.b.x = bbx_wid(&ia.ph->bx)-1;
2003: ia.ph->bx.b.y = bbx_hgt(&ia.ph->bx)-1;
2004: ia.ph->bx.a.x = ia.ph->bx.a.y = 0;
2005: };
2006: free_page_etc(&pg,IsALL&(~IsPage));
2007: }
2008: else { free_page_etc(&pg,IsALL&(~IsPage));
2009: abort("can't read document-image file");
2010: };
2011: };
2012: if(_O.in_res.x!=SHRT_MIN&&_O.in_res.y!=SHRT_MIN) {
2013: /* force input RES to given values */
2014: if(ia.ph->res_x!=0 || ia.ph->res_y!=0) {
2015: err("input: RES=%d %d overridden by -Z%d,%d\n",
2016: ia.ph->res_x,ia.ph->res_y,_O.in_res.x,_O.in_res.y);
2017: };
2018: ia.ph->res_x = _O.in_res.x;
2019: ia.ph->res_y = _O.in_res.y;
2020: };
2021: if(ia.ph->res_x<=0 || ia.ph->res_y<=0)
2022: err("input: RES=%d %d may cause problems (set using -Zx,y)",
2023: ia.ph->res_x,ia.ph->res_y);
2024:
2025: while(strlen(ia.ph->type)>0 && stat==1 && !feof(i)
2026: && !ferror(i) && !ferror(o)) {
2027: process_page(&ia,&oa);
2028: if( strcmp(ia.ph->type,"cdf")==0
2029: || strcmp(ia.ph->type,"cdf-mrlc")==0 ) {
2030: stat=CDF_next_page(ia.ph);
2031: }
2032: else { if((stat=PIC_get_hdr(ia.ph))==1) {
2033: /* enforce bitfile(9) I/O restrictions */
2034: if(_O.from_bitfile && strcmp(ia.ph->type,"bitfile")!=0)
2035: abort("-Bi means input must be picfile");
2036: if(!_O.from_bitfile && strcmp(ia.ph->type,"bitfile")==0) {
2037: /* TYPE= is missing, erroneously: silently quit */
2038: if(_O.dbg_h) err("strange input before normal EOF - ignored");
2039: strcpy(ia.ph->type,"");
2040: };
2041: };
2042: };
2043: if(_O.dbg_h && stat!=1)
2044: err("PIC_get_hdr() returns status %d",stat);
2045: };
2046:
2047: /* EOF or error */
2048: free_PIC_hdr(ia.ph);
2049: free_PIC_hdr(oa.ph);
2050: }
2051:
2052: #if FILE_TREE
2053: /* Process filenames: if NULL, use stdin/stdout; if files, read them;
2054: if directories, create a parallel file tree and process the leaves
2055: pairwise. */
2056: process_fns(i,o)
2057: char *i; /* may be NULL; not yet fopened for read */
2058: char *o; /* may be NULL; not yet fopened for write */
2059: #define dbg_ft (F)
2060: { FILE *i_fp;
2061: FILE *o_fp;
2062: char *branch;
2063: if(dbg_ft) err("processs(\"%s\",\"%s\")",i,o);
2064: branch=path_toa(&path_process.path,1);
2065: if(dbg_ft&&branch[0]!='\0') err("%s",branch);
2066: if(i==NULL||i[0]=='\0') i_fp=stdin;
2067: else if( (i_fp=fopen(i,"r"))==NULL ) {
2068: err("can't open input file %s - skip it",i);
2069: return;
2070: };
2071: if(o==NULL||o[0]=='\0') o_fp=stdout;
2072: else if( (o_fp=fopen(o,"w"))==NULL ) {
2073: err("can't open output file %s - skip it",o);
2074: return;
2075: };
2076: process_fps(i_fp,o_fp);
2077: if(i_fp!=stdin) fclose(i_fp);
2078: if(o_fp!=stdout) fclose(o_fp); else fflush(o_fp);
2079: };
2080: #else
2081: /* Process filenames: if NULL, use stdin/stdout; if files, open and process them.
2082: */
2083: process_fns(i_fn,o_fn)
2084: char *i_fn; /* may be NULL; not yet fopened for read */
2085: char *o_fn; /* may be NULL; not yet fopened for write */
2086: { FILE *i_fp;
2087: FILE *o_fp;
2088: if(i_fn==NULL||strlen(i_fn)==0) i_fp = stdin;
2089: else { if((i_fp=fopen(i_fn,"r"))==NULL)
2090: abort("can't open input file %s",i_fn);
2091: };
2092: if(o_fn==NULL||strlen(o_fn)==0) o_fp = stdout;
2093: else { if((o_fp=fopen(o_fn,"w"))==NULL)
2094: abort("can't open output file %s",o_fn);
2095: };
2096: process_fps(i_fp,o_fp);
2097: if(i_fp!=stdin) fclose(i_fp);
2098: if(o_fp!=stdout) fclose(o_fp); else fflush(o_fp);
2099: };
2100: #endif
2101:
2102: main(arc,arv)
2103: int arc; char **arv;
2104: { parse_args(arc,arv);
2105: #if FILE_TREE
2106: process_file_trees(process_fns,_O.in_fn,_O.out_fn);
2107: #else
2108: process_fns(_O.in_fn,_O.out_fn);
2109: #endif
2110: }
2111:
2112: nerr_RLE_Line(s,rl)
2113: char *s;
2114: RLE_Line *rl;
2115: { RLE_Run *r;
2116: int ri;
2117: if(rl==NULL) fprintf(stderr,"%15s RLEL NULL.\n",s);
2118: else { fprintf(stderr,"%15s RLEL y%d r%d l%d: ",s,rl->y,rl->runs,rl->len);
2119: for(ri=0,r=rl->r; ri<rl->runs; ri++,r++)
2120: fprintf(stderr,"[%d,%d] ",r->xs,r->xe);
2121: fprintf(stderr,"\n");
2122: };
2123: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.