static int decode_header_info(struct header *hdr, RSA *pkey, int *img_len) { struct little_header lhdr; /* Decode header information */ if (fb_seek_end(sizeof(lhdr)) != 0) { error("image not cryptographically enabled"); exit(NO_CRYPT); } fb_read(&lhdr, sizeof(lhdr)); if (lhdr.magic != htons(LITTLE_CRYPTO_MAGIC)) { #ifdef CONFIG_USER_NETFLASH_CRYPTO_OPTIONAL notice("WARNING: no crypto header found\n"); return 0; #else error("size magic incorrect"); exit(BAD_CRYPT_MAGIC); #endif } { unsigned short hlen = ntohs(lhdr.hlen); unsigned char tmp[hlen]; unsigned char t2[hlen]; int len; if (fb_seek_end(sizeof(lhdr) + hlen) != 0) { error("crypt header length invalid"); exit(BAD_CRYPT_LEN); } fb_read(tmp, hlen); #ifdef CONFIG_USER_NETFLASH_CRYPTO_V2 fb_meta_add(sizeof(lhdr) + hlen); *img_len = fb_len() - fb_meta_len(); #else fb_trim(sizeof(lhdr) + hlen); *img_len = fb_len(); #endif len = RSA_public_decrypt(hlen, tmp, t2, pkey, RSA_PKCS1_PADDING); if (len == -1) { error("decrypt failed"); exit(BAD_DECRYPT); } if (len != sizeof(struct header)) { error("length mismatch %d %d\n", (int)sizeof(struct header), len); } memcpy(hdr, t2, sizeof(struct header)); } if (hdr->magic != htonl(CRYPTO_MAGIC)) { error("image not cryptographically enabled"); exit(NO_CRYPT); } return 1; }
/* * OutBuild - rasterize all strokes into raster frame image */ static bool OutBuild(void) /* returns true if successful */ { register struct band *hp; /* *hp -> head of descr list */ register struct band *np; /* `hp' for next band */ register stroke *vp; /* -> rasterization descr */ if ( single_banded ) { if ( debug ) fprintf(stderr, "OutBuild: band y=%d\n", ystart); if ( fb_write( fbp, 0, ystart, buffer, buffersize/sizeof(RGBpixel) ) <= 0 ) return false; /* can't write image file */ if ( over ) { /* Read back the composite image */ if ( fb_read( fbp, 0, ystart, buffer, buffersize/sizeof(RGBpixel) ) <= 0 ) fprintf(stderr, "pl-fb: band read error\n"); } return true; } for ( hp = &band[0]; hp < bandEnd; ++hp ) if ( hp->first != NULL ) break; if ( hp == bandEnd ) return true; /* nothing to do */ for ( hp = &band[0], np = &band[1], ystart = 0; hp < bandEnd; hp = np++, ystart += lines_per_band ) { if (debug) fprintf(stderr, "OutBuild: band y=%d\n", ystart); if ( over ) { /* Read in current band */ if ( fb_read( fbp, 0, ystart, buffer, buffersize/sizeof(RGBpixel) ) <= 0 ) fprintf(stderr, "pl-fb: band read error\n"); } else { /* clear pixels in the band */ memset((char *)buffer, 0, buffersize); } while ( (vp = Dequeue( hp, &hp->first )) != NULL ) Raster( vp, np ); /* rasterize stroke */ /* Raster() either re-queued the descriptor onto the next band list or else it freed the descriptor */ if (debug) fprintf(stderr, "OutBuild: fbwrite y=%d\n", ystart); if ( fb_write( fbp, 0, ystart, buffer, buffersize/sizeof(RGBpixel) ) <= 0 ) return false; /* can't write image file */ } return true; /* success */ }
static htsmsg_t * hts_settings_load_one(const char *filename) { ssize_t n; char *mem; fb_file *fp; htsmsg_t *r = NULL; /* Open */ if (!(fp = fb_open(filename, 1, 0))) return NULL; /* Load data */ mem = malloc(fb_size(fp)+1); n = fb_read(fp, mem, fb_size(fp)); if (n >= 0) mem[n] = 0; /* Decode */ if(n == fb_size(fp)) r = htsmsg_json_deserialize(mem); /* Close */ fb_close(fp); free(mem); return r; }
int _fb_pgin(register FBIO *ifp, int pageno) { int scans, first_scan; /*fb_log( "_fb_pgin(%d)\n", pageno );*/ /* Set pixel pointer to beginning of page. */ ifp->if_pcurp = ifp->if_pbase; ifp->if_pno = pageno; ifp->if_pdirty = 0; first_scan = ifp->if_pno * PAGE_SCANS; if ( first_scan + PAGE_SCANS > ifp->if_height ) scans = ifp->if_height - first_scan; else scans = PAGE_SCANS; return fb_read( ifp, 0, first_scan, ifp->if_pbase, scans * ifp->if_width ); }
int fb_sim_bwreadrect(FBIO *ifp, int xmin, int ymin, int width, int height, unsigned char *pp) { register int y; register int tot; int got; unsigned char buf[SIMBUF_SIZE*3]; if (width > SIMBUF_SIZE) { fb_log("fb_sim_bwreadrect() width of %d exceeds internal buffer, aborting\n", width); return -SIMBUF_SIZE; /* FAIL */ } tot = 0; for (y=ymin; y < ymin+height; y++) { register int x; got = fb_read(ifp, xmin, y, buf, (size_t)width); /* Extract green chan */ for (x=0; x < width; x++) *pp++ = buf[x*3+GRN]; tot += got; if (got != width) break; } return tot; }
void paintCellFb(struct application *ap, unsigned char *pixpaint, unsigned char *pixexpendable) { int gx, gy; int gyfin, gxfin; int gxorg, gyorg; int x, y; int cnt; #if DEBUG_CELLFB brst_log("paintCellFb: expendable {%d, %d, %d}\n", pixexpendable[RED], pixexpendable[GRN], pixexpendable[BLU]); #endif gridToFb(ap->a_x, ap->a_y, &gx, &gy); gxorg = gx+1; gyorg = gy+1; gxfin = zoom == 1 ? gx+zoom+1 : gx+zoom; gyfin = zoom == 1 ? gy+zoom+1 : gy+zoom; cnt = gxfin - gxorg; for (y = gyorg; y < gyfin; y++) { if (zoom != 1 && (y - gy) % zoom == 0) continue; bu_semaphore_acquire(RT_SEM_STATS); (void) fb_read(fbiop, gxorg, y, (unsigned char *)pixbuf, cnt); bu_semaphore_release(RT_SEM_STATS); for (x = gxorg; x < gxfin; x++) { if (SAMERGB(&pixbuf[x-gxorg][0], pixexpendable) ) { #if DEBUG_CELLFB brst_log("Clobbering:<%d, %d>{%d, %d, %d}\n", x, y, pixbuf[x-gxorg][RED], pixbuf[x-gxorg][GRN], pixbuf[x-gxorg][BLU]); #endif COPYRGB(&pixbuf[x-gxorg][0], pixpaint); } #if DEBUG_CELLFB else brst_log("Preserving:<%d, %d>{%d, %d, %d}\n", x, y, pixbuf[x-gxorg][RED], pixbuf[x-gxorg][GRN], pixbuf[x-gxorg][BLU]); #endif } bu_semaphore_acquire(RT_SEM_STATS); (void) fb_write(fbiop, gxorg, y, (unsigned char *)pixbuf, cnt); bu_semaphore_release(RT_SEM_STATS); #if DEBUG_CELLFB brst_log("paintCellFb: fb_write(%d, %d)\n", x, y); #endif } return; }
int main(int argc, char **argv) { int x, y; int xin, yin; /* number of sceen output lines */ height = width = 512; /* Defaults */ if ( !get_args( argc, argv ) ) { (void)fputs(usage, stderr); bu_exit( 1, NULL ); } /* Open Display Device */ if ((fbp = fb_open(framebuffer, width, height )) == NULL ) { fprintf( stderr, "fb_open failed\n"); bu_exit( 1, NULL ); } /* determine "reasonable" behavior */ xin = fb_getwidth(fbp) - scr_xoff; if ( xin < 0 ) xin = 0; if ( xin > width ) xin = width; yin = fb_getheight(fbp) - scr_yoff; if ( yin < 0 ) yin = 0; if ( yin > height ) yin = height; for ( y = scr_yoff; y < scr_yoff + yin; y++ ) { if ( inverse ) { (void)fb_read( fbp, scr_xoff, fb_getheight(fbp)-1-y, inbuf, xin ); } else { (void)fb_read( fbp, scr_xoff, y, inbuf, xin ); } for ( x = 0; x < xin; x++ ) { obuf[x] = (((int)inbuf[3*x+RED]) + ((int)inbuf[3*x+GRN]) + ((int)inbuf[3*x+BLU])) / 3; } fwrite( &obuf[0], sizeof( char ), xin, outfp ); } fb_close( fbp ); bu_exit( 0, NULL ); }
/* Read a line */ char *fb_gets ( fb_file *fp, void *buf, size_t count ) { ssize_t c = 0, err; while ((err = fb_read(fp, buf+c, 1)) && c < (count-1)) { char b = ((char*)buf)[c]; c++; if (b == '\n' || b == '\0') break; } if (err < 0) return NULL; ((char*)buf)[c] = '\0'; return buf; }
/* * A routine to simulate the effect of fb_readrect() when a * particular display does not handle it. */ int fb_sim_readrect(FBIO *ifp, int xmin, int ymin, int width, int height, unsigned char *pp) { register int y; register int tot; int got; tot = 0; for (y=ymin; y < ymin+height; y++) { got = fb_read(ifp, xmin, y, pp, (size_t)width); if (got < 0) { fb_log("fb_sim_readrect() y=%d unexpected EOF\n", y); break; } tot += got; if (got != width) { fb_log("fb_sim_readrect() y=%d, read of %d got %d pixels, aborting\n", y, width, got); break; } pp += width * sizeof(RGBpixel); } return tot; }
int main(int argc, char **argv) { FBIO *fbp; int y; unsigned char *scanline; /* 1 scanline pixel buffer */ int scanbytes; /* # of bytes of scanline */ int scanpix; /* # of pixels of scanline */ ColorMap cmap; /* libfb color map */ char usage[] = "\ Usage: fb-pix [-h -i -c] [-F framebuffer]\n\ [-s squaresize] [-w width] [-n height] [file.pix]\n"; screen_height = screen_width = 512; /* Defaults */ if (!get_args(argc, argv)) { (void)fputs(usage, stderr); bu_exit(1, NULL); } #if defined(_WIN32) && !defined(__CYGWIN__) setmode(fileno(stdout), O_BINARY); #endif scanpix = screen_width; scanbytes = scanpix * sizeof(RGBpixel); if ((scanline = (unsigned char *)malloc(scanbytes)) == RGBPIXEL_NULL) { fprintf(stderr, "fb-pix: malloc(%d) failure\n", scanbytes); bu_exit(2, NULL); } if ((fbp = fb_open(framebuffer, screen_width, screen_height)) == NULL) { bu_exit(12, NULL); } if (screen_height > fb_getheight(fbp)) screen_height = fb_getheight(fbp); if (screen_width > fb_getwidth(fbp)) screen_width = fb_getwidth(fbp); if (crunch) { if (fb_rmap(fbp, &cmap) == -1) { crunch = 0; } else if (fb_is_linear_cmap(&cmap)) { crunch = 0; } } if (!inverse) { /* Regular -- read bottom to top */ for (y=0; y < screen_height; y++) { fb_read(fbp, 0, y, scanline, screen_width); if (crunch) cmap_crunch((RGBpixel *)scanline, scanpix, &cmap); if (fwrite((char *)scanline, scanbytes, 1, outfp) != 1) { perror("fwrite"); break; } } } else { /* Inverse -- read top to bottom */ for (y = screen_height-1; y >= 0; y--) { fb_read(fbp, 0, y, scanline, screen_width); if (crunch) cmap_crunch((RGBpixel *)scanline, scanpix, &cmap); if (fwrite((char *)scanline, scanbytes, 1, outfp) != 1) { perror("fwrite"); break; } } } fb_close(fbp); return 0; }
/* * M A I N * * Parse arguments, valid ones are: * name of file to plot (instead of STDIN) * -d for debugging statements * * Default (no arguments) action is to plot STDIN on current FB. */ int main(int argc, char **argv) { Nscanlines = Npixels = 512; if ( !get_args( argc, argv ) ) { (void)fputs(usage, stderr); bu_exit( 1, NULL ); } /* Open frame buffer, adapt to slightly smaller ones */ if ( (fbp = fb_open(framebuffer, Npixels, Nscanlines)) == FBIO_NULL ) { fprintf(stderr, "pl-fb: fb_open failed\n"); bu_exit(1, NULL); } Npixels = fb_getwidth(fbp); Nscanlines = fb_getheight(fbp); if ( immediate ) { lines_per_band = Nscanlines; if ( !over ) fb_clear( fbp, RGBPIXEL_NULL ); } else if ( Nscanlines <= 512 ) { /* make one full size band */ lines_per_band = Nscanlines; single_banded = 1; } /* * Handle image-size specific initializations */ if ( (Nscanlines % lines_per_band) != 0 ) { /* round it down - only necessary if buffered? */ Nscanlines = (Nscanlines / lines_per_band) * lines_per_band; } space.left = space.right = 0; space.right = Npixels; space.top = Nscanlines; delta = Nscanlines; deltao2 = Nscanlines/2; buffersize = lines_per_band*Npixels*sizeof(RGBpixel); if ( (buffer = (unsigned char *)malloc(buffersize)) == RGBPIXEL_NULL) { fprintf(stderr, "pl-fb: malloc error\n"); bu_exit(1, NULL); } /* Extra band protects against requeueing off the top */ band = (struct band *)malloc((BANDSLOP)*sizeof(struct band)); if ( band == (struct band *)0 ) { fprintf(stderr, "pl-fb: malloc error2\n"); bu_exit(1, NULL); } memset((char *)band, 0, (BANDSLOP)*sizeof(struct band)); bandEnd = &band[BANDS]; if ( single_banded && over ) { /* Read in initial screen */ if ( fb_read( fbp, 0, 0, buffer, buffersize/sizeof(RGBpixel) ) <= 0 ) fprintf(stderr, "pl-fb: band read error\n"); } if ( debug ) fprintf(stderr, "pl-fb output of %s\n", filename); SetSigs(); /* set signal catchers */ (void)DoFile( ); /* plot it */ bu_exit(0, NULL); }
/** * beginning of a frame */ void view_2init(struct application *UNUSED(ap), char *UNUSED(framename)) { int i; /* * Per_processor_chuck specifies the number of pixels rendered per * each pass of a worker. By making this value equal to the width * of the image, each worker will render one scanline at a time. */ per_processor_chunk = width; /* * Use three bytes per pixel. */ pixsize = 3; /* * Set the hit distance difference necessary to trigger an edge. * This algorithm was stolen from lgt, I may make it settable * later. */ if (max_dist < .00001) max_dist = (cell_width*ARCTAN_87)+2; /* * Determine if the framebuffer is readable. */ if (overlay || blend) if (fb_read(fbp, 0, 0, fb_bg_color, 1) < 0) bu_exit(EXIT_FAILURE, "rt_edge: specified framebuffer is not readable, cannot merge.\n"); /* * Create a cell to store current data for next cells left side. * Create a edge flag buffer for each processor. Create a * scanline buffer for each processor. */ for (i = 0; i < npsw; ++i) { if (saved[i] == NULL) BU_ALLOC(saved[i], struct cell); if (writeable[i] == NULL) writeable[i] = (unsigned char *) bu_calloc(1, per_processor_chunk, "writeable pixel flag buffer"); if (scanline[i] == NULL) scanline[i] = (unsigned char *) bu_calloc(per_processor_chunk, pixsize, "scanline buffer"); /* * If blending is desired, create scanline buffers to hold the * read-in lines from the framebuffer. */ if (blend && blendline[i] == NULL) blendline[i] = (unsigned char *) bu_calloc(per_processor_chunk, pixsize, "blend buffer"); } /* * If operating in overlay mode, we want the rtedge background * color to be the shaded images background. This sets the bg * color automatically, but assumes that pixel 0, 0 is * background. If not, the user can set it manually (so long as it * isn't 0 0 1!). * */ if (overlay && bgcolor[RED] == 0 && bgcolor[GRN] == 0 && bgcolor[BLU] == 1) { bgcolor[RED] = fb_bg_color[RED]; bgcolor[GRN] = fb_bg_color[GRN]; bgcolor[BLU] = fb_bg_color[BLU]; } return; }
/** * action performed at the end of each scanline */ void view_eol(struct application *ap) { int cpu = ap->a_resource->re_cpu; int i; if (overlay) { /* * Overlay mode. Check if the pixel is an edge. If so, write * it to the framebuffer. */ for (i = 0; i < per_processor_chunk; ++i) { if (writeable[cpu][i]) { /* * Write this pixel */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, i, ap->a_y, &scanline[cpu][i*3], 1); bu_semaphore_release(BU_SEM_SYSCALL); } } return; } else if (blend) { /* * Blend mode. * * Read a line from the existing framebuffer, convert to HSV, * manipulate, and put the results in the scanline as RGB. */ int replace_down = 0; /* flag that specifies if the pixel in the * scanline below must be replaced. */ RGBpixel rgb; fastf_t hsv[3]; bu_semaphore_acquire(BU_SEM_SYSCALL); if (fb_read(fbp, 0, ap->a_y, blendline[cpu], per_processor_chunk) < 0) bu_exit(EXIT_FAILURE, "rtedge: error reading from framebuffer.\n"); bu_semaphore_release(BU_SEM_SYSCALL); for (i = 0; i < per_processor_chunk; ++i) { /* * Is this pixel an edge? */ if (writeable[cpu][i]) { /* * The pixel is an edge, retrieve the appropriate * pixel from the line buffer and convert it to HSV. */ rgb[RED] = blendline[cpu][i*3+RED]; rgb[GRN] = blendline[cpu][i*3+GRN]; rgb[BLU] = blendline[cpu][i*3+BLU]; /* * Is the pixel in the blendline array the background * color? If so, look left and down to determine which * pixel is the "source" of the edge. Unless, of * course, we are on the bottom scanline or the * leftmost column (x=y=0) */ if (i != 0 && ap->a_y != 0 && !diffpixel(rgb, fb_bg_color)) { RGBpixel left; RGBpixel down; left[RED] = blendline[cpu][(i-1)*3+RED]; left[GRN] = blendline[cpu][(i-1)*3+GRN]; left[BLU] = blendline[cpu][(i-1)*3+BLU]; bu_semaphore_acquire(BU_SEM_SYSCALL); fb_read(fbp, i, ap->a_y - 1, down, 1); bu_semaphore_release(BU_SEM_SYSCALL); if (diffpixel(left, fb_bg_color)) { /* * Use this one. */ rgb[RED] = left[RED]; rgb[GRN] = left[GRN]; rgb[BLU] = left[BLU]; } else if (diffpixel(down, fb_bg_color)) { /* * Use the pixel from the scanline below */ replace_down = 1; rgb[RED] = down[RED]; rgb[GRN] = down[GRN]; rgb[BLU] = down[BLU]; } } /* * Convert to HSV */ bu_rgb_to_hsv(rgb, hsv); /* * Now perform the manipulations. */ hsv[VAL] *= 3.0; hsv[SAT] /= 3.0; if (hsv[VAL] > 1.0) { fastf_t d = hsv[VAL] - 1.0; hsv[VAL] = 1.0; hsv[SAT] -= d; hsv[SAT] = hsv[SAT] >= 0.0 ? hsv[SAT] : 0.0; } /* * Convert back to RGB. */ bu_hsv_to_rgb(hsv, rgb); if (replace_down) { /* * Write this pixel immediately, do not put it * into the blendline since it corresponds to the * wrong scanline. */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, i, ap->a_y, rgb, 1); bu_semaphore_release(BU_SEM_SYSCALL); replace_down = 0; } else { /* * Put this pixel back into the blendline array. * We'll push it to the buffer when the entire * scanline has been processed. */ blendline[cpu][i*3+RED] = rgb[RED]; blendline[cpu][i*3+GRN] = rgb[GRN]; blendline[cpu][i*3+BLU] = rgb[BLU]; } } /* end "if this pixel is an edge" */ } /* end pixel loop */ /* * Write the blendline to the framebuffer. */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, 0, ap->a_y, blendline[cpu], per_processor_chunk); bu_semaphore_release(BU_SEM_SYSCALL); return; } /* end blend */ if (fbp != FBIO_NULL) { /* * Simple whole scanline write to a framebuffer. */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, 0, ap->a_y, scanline[cpu], per_processor_chunk); bu_semaphore_release(BU_SEM_SYSCALL); } if (outputfile != NULL) { /* * Write to a file. */ bu_semaphore_acquire(BU_SEM_SYSCALL); /* TODO : Add double type data to maintain resolution */ icv_writeline(bif, ap->a_y, scanline[cpu], ICV_DATA_UCHAR); bu_semaphore_release(BU_SEM_SYSCALL); } if (fbp == FBIO_NULL && outputfile == NULL) bu_log("rtedge: strange, no end of line actions taken.\n"); return; }
HIDDEN void do_Char(int c, int xpos, int ypos, int odd) { register int i, j; int base; int totwid = font.width; int down; static float resbuf[FONTBUFSZ]; static RGBpixel fbline[FONTBUFSZ]; #if DEBUG_STRINGS fb_log( "do_Char: c='%c' xpos=%d ypos=%d odd=%d\n", c, xpos, ypos, odd ); #endif /* read in character bit map, with two blank lines on each end */ for (i = 0; i < 2; i++) clear_buf (totwid, filterbuf[i]); for (i = font.height + 1; i >= 2; i--) fill_buf (font.width, filterbuf[i]); for (i = font.height + 2; i < font.height + 4; i++) clear_buf (totwid, filterbuf[i]); (void)SignedChar( font.dir[c].up ); down = SignedChar( font.dir[c].down ); /* Initial base line for filtering depends on odd flag. */ base = (odd ? 1 : 2); /* Produce a RGBpixel buffer from a description of the character and the read back data from the frame buffer for anti-aliasing. */ for (i = font.height + base; i >= base; i--) { squash( filterbuf[i - 1], /* filter info */ filterbuf[i], filterbuf[i + 1], resbuf, totwid + 4 ); fb_read( fbp, xpos, ypos - down + i, (unsigned char *)fbline, totwid+3); for (j = 0; j < (totwid + 3) - 1; j++) { register int tmp; /* EDITOR'S NOTE : do not rearrange this code, the SUN compiler can't handle more complex expressions. */ tmp = fbline[j][RED] & 0377; fbline[j][RED] = (int)(paint[RED]*resbuf[j]+(1-resbuf[j])*tmp); fbline[j][RED] &= 0377; tmp = fbline[j][GRN] & 0377; fbline[j][GRN] = (int)(paint[GRN]*resbuf[j]+(1-resbuf[j])*tmp); fbline[j][GRN] &= 0377; tmp = fbline[j][BLU] & 0377; fbline[j][BLU] = (int)(paint[BLU]*resbuf[j]+(1-resbuf[j])*tmp); fbline[j][BLU] &= 0377; } fb_write( fbp, xpos, ypos - down + i, (unsigned char *)fbline, totwid+3 ); } return; }
int main(int argc, char **argv) { /* Plant signal catcher. */ { static int getsigs[] = { /* signals to catch */ #ifdef SIGHUP SIGHUP, /* hangup */ #endif #ifdef SIGINT SIGINT, /* interrupt */ #endif #ifdef SIGQUIT SIGQUIT, /* quit */ #endif #ifdef SIGPIPE SIGPIPE, /* write on a broken pipe */ #endif #ifdef SIGTERM SIGTERM, /* software termination signal */ #endif 0 }; int i; for (i = 0; getsigs[i] != 0; ++i) if (signal(getsigs[i], SIG_IGN) != SIG_IGN) (void)signal(getsigs[i], Sig_Catcher); } /* Process arguments. */ { int c; bool_t errors = 0; while ((c = bu_getopt(argc, argv, OPTSTR)) != -1) switch (c) { default: /* '?': invalid option */ errors = 1; break; case 'a': /* -a */ sample = 1; break; case 'f': /* -f in_fb */ src_file = bu_optarg; break; case 'F': /* -F out_fb */ dst_file = bu_optarg; break; case 'n': /* -n height */ if ((src_height = atoi(bu_optarg)) <= 0) errors = 1; break; case 'N': /* -N height */ if ((dst_height = atoi(bu_optarg)) <= 0) errors = 1; break; case 's': /* -s size */ if ((src_height = src_width = atoi(bu_optarg)) <= 0 ) errors = 1; break; case 'S': /* -S size */ if ((dst_height = dst_width = atoi(bu_optarg)) <= 0 ) errors = 1; break; case 'v': verbose = 1; break; case 'w': /* -w width */ if ((src_width = atoi(bu_optarg)) <= 0) errors = 1; break; case 'W': /* -W width */ if ((dst_width = atoi(bu_optarg)) <= 0) errors = 1; break; case 'x': /* -x x_scale */ if ((x_scale = atof(bu_optarg)) <= 0) { Message("Nonpositive x scale factor"); errors = 1; } break; case 'y': /* -y y_scale */ if ((y_scale = atof(bu_optarg)) <= 0) { Message("Nonpositive y scale factor"); errors = 1; } break; } if (argc == 1 && isatty(fileno(stdin)) && isatty(fileno(stdout))) errors = 1; if (errors) bu_exit(1, "Usage: %s\n%s\n%s\n", USAGE1, USAGE2, USAGE3); } if (bu_optind < argc) { /* dst_file */ if (bu_optind < argc - 1 || dst_file != NULL) { bu_log("Usage: %s\n%s\n%s", USAGE1, USAGE2, USAGE3); Stretch_Fatal("Can't handle multiple output frame buffers!"); } dst_file = argv[bu_optind]; } if (dst_file == NULL) dst_file = getenv("FB_FILE"); /* Figure out what scale factors to use before messing up size info. */ if (x_scale < 0.0) { if (src_width == 0 || dst_width == 0) x_scale = 1.0; else x_scale = (double)dst_width / (double)src_width; } if (y_scale < 0.0) { if (src_height == 0 || dst_height == 0) y_scale = 1.0; else y_scale = (double)dst_height / (double)src_height; } if (verbose) Message("Scale factors %gx%g", x_scale, y_scale); /* Open frame buffer(s) for unbuffered input/output. */ if ((src_fbp = fb_open(src_file == NULL ? dst_file : src_file, src_width, src_height ) ) == FB_NULL ) Stretch_Fatal("Couldn't open input image"); else { int wt, ht; /* actual frame buffer size */ /* Use smaller input size in preference to requested size. */ if ((wt = fb_getwidth(src_fbp)) < src_width) src_width = wt; if ((ht = fb_getheight(src_fbp)) < src_height) src_height = ht; if (verbose) Message("Source image %dx%d", src_width, src_height); if (dst_width == 0) dst_width = src_width * x_scale + EPSILON; if (dst_height == 0) dst_height = src_height * y_scale + EPSILON; if (verbose) Message("Requested output size %dx%d", dst_width, dst_height ); if (src_file == NULL || (dst_file != NULL && BU_STR_EQUAL(src_file, dst_file)) ) dst_fbp = src_fbp; /* No No No Not a Second Time */ else if ((dst_fbp = fb_open(dst_file, dst_width, dst_height)) == FB_NULL ) Stretch_Fatal("Couldn't open output frame buffer"); /* Use smaller output size in preference to requested size. */ if ((wt = fb_getwidth(dst_fbp)) < dst_width) dst_width = wt; if ((ht = fb_getheight(dst_fbp)) < dst_height) dst_height = ht; if (verbose) Message("Destination image %dx%d", dst_width, dst_height ); } /* Determine compression/expansion directions. */ x_compress = x_scale < 1 - EPSILON; y_compress = y_scale < 1 - EPSILON; /* Allocate input/output scan line buffers. These could overlap, but I decided to keep them separate for simplicity. The algorithms are arranged so that source and destination can access the same image; if at some future time offsets are supported, that would no longer hold. calloc is used instead of malloc just to avoid integer overflow. */ if ((src_buf = (unsigned char *)calloc( y_compress ? (int)(1 / y_scale + 1 - EPSILON) * src_width : src_width, sizeof(RGBpixel) ) ) == NULL || (dst_buf = (unsigned char *)calloc( y_compress ? dst_width : (int)(y_scale + 1 - EPSILON) * dst_width, sizeof(RGBpixel) ) ) == NULL ) Stretch_Fatal("Insufficient memory for scan line buffers."); #define Src(x, y) (&src_buf[(x) + src_width * (y) * sizeof(RGBpixel)]) #define Dst(x, y) (&dst_buf[(x) + dst_width * (y) * sizeof(RGBpixel)]) /* Do the horizontal/vertical expansion/compression. I wanted to merge these but didn't like the extra bookkeeping overhead in the loops. */ if (x_compress && y_compress) { int src_x, src_y; /* source rect. pixel coords. */ int dst_x, dst_y; /* destination pixel coords. */ int top_x, top_y; /* source rect. upper bounds */ int bot_x, bot_y; /* source rect. lower bounds */ /* Compute coords. of source rectangle and destination pixel. */ dst_y = 0; ccyloop: if (dst_y >= dst_height) goto done; /* that's all folks */ bot_y = dst_y / y_scale + EPSILON; if ((top_y = (dst_y + 1) / y_scale + EPSILON) > src_height) top_y = src_height; if (top_y <= bot_y) { /* End of image. */ /* Clear beginning of output scan line buffer. */ dst_x = src_width * y_scale + EPSILON; if (dst_x < dst_width) ++dst_x; /* sometimes needed */ while (--dst_x >= 0) { assert(dst_x < dst_width); Dst(dst_x, 0)[RED] = 0; Dst(dst_x, 0)[GRN] = 0; Dst(dst_x, 0)[BLU] = 0; } /* Clear out top margin. */ for (; dst_y < dst_height; ++dst_y) if (fb_write(dst_fbp, 0, dst_y, (unsigned char *)Dst(0, 0), dst_width ) == -1 ) Stretch_Fatal("Error writing top margin"); goto done; /* that's all folks */ } assert(0 <= bot_y && bot_y < top_y && top_y <= src_height); assert(0 <= dst_y && dst_y <= bot_y); assert(top_y - bot_y <= (int)(1 / y_scale + 1 - EPSILON)); /* Fill input scan line buffer. */ for (src_y = bot_y; src_y < top_y; ++src_y) if (fb_read(src_fbp, 0, src_y, (unsigned char *)Src(0, src_y - bot_y), src_width ) == -1 ) Stretch_Fatal("Error reading scan line"); dst_x = 0; ccxloop: if (dst_x >= dst_width) goto ccflush; bot_x = dst_x / x_scale + EPSILON; if ((top_x = (dst_x + 1) / x_scale + EPSILON) > src_width) top_x = src_width; if (top_x <= bot_x) { ccflush: /* End of band; flush buffer. */ if (fb_write(dst_fbp, 0, dst_y, (unsigned char *)Dst(0, 0), dst_width ) == -1 ) Stretch_Fatal("Error writing scan line"); ++dst_y; goto ccyloop; } assert(0 <= bot_x && bot_x < top_x && top_x <= src_width); assert(0 <= dst_x && dst_x <= bot_x); assert(top_x - bot_x <= (int)(1 / x_scale + 1 - EPSILON)); /* Copy sample or averaged source pixel(s) to destination. */ if (sample) { Dst(dst_x, 0)[RED] = Src(bot_x, 0)[RED]; Dst(dst_x, 0)[GRN] = Src(bot_x, 0)[GRN]; Dst(dst_x, 0)[BLU] = Src(bot_x, 0)[BLU]; } else { int sum[3]; /* pixel value accumulator */ float tally; /* # of pixels accumulated */ /* "Read in" source rectangle and average pixels. */ sum[RED] = sum[GRN] = sum[BLU] = 0; for (src_y = top_y - bot_y; --src_y >= 0;) for (src_x = bot_x; src_x < top_x; ++src_x) { sum[RED] += Src(src_x, src_y)[RED]; sum[GRN] += Src(src_x, src_y)[GRN]; sum[BLU] += Src(src_x, src_y)[BLU]; } tally = (top_x - bot_x) * (top_y - bot_y); assert(tally > 0.0); Dst(dst_x, 0)[RED] = sum[RED] / tally + 0.5; Dst(dst_x, 0)[GRN] = sum[GRN] / tally + 0.5; Dst(dst_x, 0)[BLU] = sum[BLU] / tally + 0.5; } ++dst_x; goto ccxloop; } else if (x_compress && !y_compress) { int src_x, src_y; /* source rect. pixel coords. */ int dst_x, dst_y; /* dest. rect. pixel coords. */ int bot_x, top_x; /* source rectangle bounds */ int bot_y, top_y; /* destination rect. bounds */ /* Compute coords. of source and destination rectangles. */ src_y = (dst_height - 1) / y_scale + EPSILON; ceyloop: if (src_y < 0) goto done; /* that's all folks */ bot_y = src_y * y_scale + EPSILON; if ((top_y = (src_y + 1) * y_scale + EPSILON) > dst_height) top_y = dst_height; assert(0 <= src_y && src_y <= bot_y && src_y < src_height); assert(bot_y < top_y && top_y <= dst_height); assert(top_y - bot_y <= (int)(y_scale + 1 - EPSILON)); /* Fill input scan line buffer. */ if (fb_read(src_fbp, 0, src_y, (unsigned char *)Src(0, 0), src_width ) == -1 ) Stretch_Fatal("Error reading scan line"); dst_x = 0; cexloop: if (dst_x >= dst_width) goto ceflush; bot_x = dst_x / x_scale + EPSILON; if ((top_x = (dst_x + 1) / x_scale + EPSILON) > src_width) top_x = src_width; if (top_x <= bot_x) { ceflush: /* End of band; flush buffer. */ for (dst_y = top_y; --dst_y >= bot_y;) if (fb_write(dst_fbp, 0, dst_y, (unsigned char *)Dst(0, dst_y - bot_y ), dst_width ) == -1 ) Stretch_Fatal("Error writing scan line"); --src_y; goto ceyloop; } assert(0 <= bot_x && bot_x < top_x && top_x <= src_width); assert(0 <= dst_x && dst_x <= bot_x); assert(top_x - bot_x <= (int)(1 / x_scale + 1 - EPSILON)); /* Replicate sample or averaged source pixel(s) to dest. */ if (sample) { for (dst_y = top_y - bot_y; --dst_y >= 0;) { Dst(dst_x, dst_y)[RED] = Src(bot_x, 0)[RED]; Dst(dst_x, dst_y)[GRN] = Src(bot_x, 0)[GRN]; Dst(dst_x, dst_y)[BLU] = Src(bot_x, 0)[BLU]; } } else { int sum[3]; /* pixel value accumulator */ float tally; /* # of pixels accumulated */ /* "Read in" source rectangle and average pixels. */ sum[RED] = sum[GRN] = sum[BLU] = 0; for (src_x = bot_x; src_x < top_x; ++src_x) { sum[RED] += Src(src_x, 0)[RED]; sum[GRN] += Src(src_x, 0)[GRN]; sum[BLU] += Src(src_x, 0)[BLU]; } tally = top_x - bot_x; assert(tally > 0.0); sum[RED] = sum[RED] / tally + 0.5; sum[GRN] = sum[GRN] / tally + 0.5; sum[BLU] = sum[BLU] / tally + 0.5; for (dst_y = top_y - bot_y; --dst_y >= 0;) { Dst(dst_x, dst_y)[RED] = sum[RED]; Dst(dst_x, dst_y)[GRN] = sum[GRN]; Dst(dst_x, dst_y)[BLU] = sum[BLU]; } } ++dst_x; goto cexloop; } else if (!x_compress && y_compress) { int src_x, src_y; /* source rect. pixel coords. */ int dst_x, dst_y; /* dest. rect. pixel coords. */ int bot_x, top_x; /* destination rect. bounds */ int bot_y, top_y; /* source rectangle bounds */ assert(dst_width >= src_width); /* (thus no right margin) */ /* Compute coords. of source and destination rectangles. */ dst_y = 0; ecyloop: if (dst_y >= dst_height) goto done; /* that's all folks */ bot_y = dst_y / y_scale + EPSILON; if ((top_y = (dst_y + 1) / y_scale + EPSILON) > src_height) top_y = src_height; if (top_y <= bot_y) { /* End of image. */ /* Clear output scan line buffer. */ for (dst_x = dst_width; --dst_x >= 0;) { Dst(dst_x, 0)[RED] = 0; Dst(dst_x, 0)[GRN] = 0; Dst(dst_x, 0)[BLU] = 0; } /* Clear out top margin. */ for (; dst_y < dst_height; ++dst_y) if (fb_write(dst_fbp, 0, dst_y, (unsigned char *)Dst(0, 0), dst_width ) == -1 ) Stretch_Fatal("Error writing top margin"); goto done; /* that's all folks */ } assert(0 <= bot_y && bot_y < top_y && top_y <= src_height); assert(0 <= dst_y && dst_y <= bot_y); assert(top_y - bot_y <= (int)(1 / y_scale + 1 - EPSILON)); /* Fill input scan line buffer. */ for (src_y = bot_y; src_y < top_y; ++src_y) if (fb_read(src_fbp, 0, src_y, (unsigned char *)Src(0, src_y - bot_y), src_width ) == -1 ) Stretch_Fatal("Error reading scan line"); src_x = (dst_width - 1) / x_scale + EPSILON; ecxloop: if (src_x < 0) { /* End of band; flush buffer. */ if (fb_write(dst_fbp, 0, dst_y, (unsigned char *)Dst(0, 0), dst_width ) == -1 ) Stretch_Fatal("Error writing scan line"); ++dst_y; goto ecyloop; } bot_x = src_x * x_scale + EPSILON; if ((top_x = (src_x + 1) * x_scale + EPSILON) > dst_width) top_x = dst_width; assert(0 <= src_x && src_x <= bot_x && src_x <= src_width); assert(bot_x < top_x && top_x <= dst_width); assert(top_x - bot_x <= (int)(x_scale + 1 - EPSILON)); /* Replicate sample or averaged source pixel(s) to dest. */ if (sample) { for (dst_x = top_x; --dst_x >= bot_x;) { Dst(dst_x, 0)[RED] = Src(src_x, 0)[RED]; Dst(dst_x, 0)[GRN] = Src(src_x, 0)[GRN]; Dst(dst_x, 0)[BLU] = Src(src_x, 0)[BLU]; } } else { int sum[3]; /* pixel value accumulator */ float tally; /* # of pixels accumulated */ /* "Read in" source rectangle and average pixels. */ sum[RED] = sum[GRN] = sum[BLU] = 0; for (src_y = top_y - bot_y; --src_y >= 0;) { sum[RED] += Src(src_x, src_y)[RED]; sum[GRN] += Src(src_x, src_y)[GRN]; sum[BLU] += Src(src_x, src_y)[BLU]; } tally = top_y - bot_y; assert(tally > 0.0); sum[RED] = sum[RED] / tally + 0.5; sum[GRN] = sum[GRN] / tally + 0.5; sum[BLU] = sum[BLU] / tally + 0.5; for (dst_x = top_x; --dst_x >= bot_x;) { Dst(dst_x, 0)[RED] = sum[RED]; Dst(dst_x, 0)[GRN] = sum[GRN]; Dst(dst_x, 0)[BLU] = sum[BLU]; } } --src_x; goto ecxloop; } else if (!x_compress && !y_compress) { int src_x, src_y; /* source pixel coords. */ int dst_x, dst_y; /* dest. rect. pixel coords. */ int bot_x, bot_y; /* dest. rect. lower bounds */ int top_x, top_y; /* dest. rect. upper bounds */ assert(dst_width >= src_width); /* (thus no right margin) */ /* Compute coords. of source and destination rectangles. */ src_y = (dst_height - 1) / y_scale + EPSILON; eeyloop: if (src_y < 0) goto done; /* that's all folks */ bot_y = src_y * y_scale + EPSILON; if ((top_y = (src_y + 1) * y_scale + EPSILON) > dst_height) top_y = dst_height; assert(0 <= src_y && src_y <= bot_y && src_y < src_height); assert(bot_y < top_y && top_y <= dst_height); assert(top_y - bot_y <= (int)(y_scale + 1 - EPSILON)); /* Fill input scan line buffer. */ if (fb_read(src_fbp, 0, src_y, (unsigned char *)Src(0, 0), src_width ) == -1 ) Stretch_Fatal("Error reading scan line"); src_x = (dst_width - 1) / x_scale + EPSILON; eexloop: if (src_x < 0) { /* End of band; flush buffer. */ for (dst_y = top_y; --dst_y >= bot_y;) if (fb_write(dst_fbp, 0, dst_y, (unsigned char *)Dst(0, dst_y - bot_y ), dst_width ) == -1 ) Stretch_Fatal("Error writing scan line"); --src_y; goto eeyloop; } bot_x = src_x * x_scale + EPSILON; if ((top_x = (src_x + 1) * x_scale + EPSILON) > dst_width) top_x = dst_width; assert(0 <= src_x && src_x <= bot_x && src_x <= src_width); assert(bot_x < top_x && top_x <= dst_width); assert(top_x - bot_x <= (int)(x_scale + 1 - EPSILON)); /* Replicate sample source pixel to destination. */ for (dst_y = top_y - bot_y; --dst_y >= 0;) for (dst_x = top_x; --dst_x >= bot_x;) { Dst(dst_x, dst_y)[RED] = Src(src_x, 0)[RED]; Dst(dst_x, dst_y)[GRN] = Src(src_x, 0)[GRN]; Dst(dst_x, dst_y)[BLU] = Src(src_x, 0)[BLU]; } --src_x; goto eexloop; } done: /* Close the frame buffers. */ assert(src_fbp != FB_NULL && dst_fbp != FB_NULL); if (fb_close(src_fbp) == -1) Message("Error closing input frame buffer"); if (dst_fbp != src_fbp && fb_close(dst_fbp) == -1) Message("Error closing output frame buffer"); return 0; }
void do_char(struct vfont *vfp, struct vfont_dispatch *vdp, int x, int y) { int i, j; int base; int totwid = width; int ln; static float resbuf[FONTBUFSZ]; static RGBpixel fbline[FONTBUFSZ]; int bytes_wide; /* # bytes/row in bitmap */ bytes_wide = (width+7)>>3; /* Read in the character bit map, with two blank lines on each end. */ for (i = 0; i < 2; i++) memset((char *)&filterbuf[i][0], 0, (totwid+4)*sizeof(int)); for (ln=0, i = height + 1; i >= 2; i--, ln++) fill_buf (width, &filterbuf[i][0], &vfp->vf_bits[vdp->vd_addr + bytes_wide*ln]); for (i = height + 2; i < height + 4; i++) memset((char *)&filterbuf[i][0], 0, (totwid+4)*sizeof(int)); /* Initial base line for filtering depends on odd flag. */ if (vdp->vd_down % 2) base = 1; else base = 2; /* Produce a RGBpixel buffer from a description of the character * and the read back data from the frame buffer for anti-aliasing. */ for (i = height + base; i >= base; i--) { squash(filterbuf[i - 1], /* filter info */ filterbuf[i], filterbuf[i + 1], resbuf, totwid + 4 ); fb_read(fbp, x, y - vdp->vd_down + i, (unsigned char *)fbline, totwid+3); for (j = 0; j < (totwid + 3) - 1; j++) { int tmp; /* EDITOR'S NOTE : do not rearrange this code, the SUN * compiler can't handle more complex expressions. */ tmp = fbline[j][RED] & 0377; fbline[j][RED] = (int)(pixcolor[RED]*resbuf[j]+(1-resbuf[j])*tmp); fbline[j][RED] &= 0377; tmp = fbline[j][GRN] & 0377; fbline[j][GRN] = (int)(pixcolor[GRN]*resbuf[j]+(1-resbuf[j])*tmp); fbline[j][GRN] &= 0377; tmp = fbline[j][BLU] & 0377; fbline[j][BLU] = (int)(pixcolor[BLU]*resbuf[j]+(1-resbuf[j])*tmp); fbline[j][BLU] &= 0377; } if (fb_write(fbp, x, y-vdp->vd_down+i, (unsigned char *)fbline, totwid+3) < totwid+3) { fprintf(stderr, "fblabel: pixel write error\n"); bu_exit(1, NULL); } } }
int main(int argc, char **argv) { FBIO *fbp; int i; int file_width; /* unclipped width of rectangle */ int file_skiplen; /* # of pixels to skip on l.h.s. */ int screen_xbase; /* screen X of l.h.s. of rectangle */ int screen_xlen; /* clipped len of rectangle */ int ncolors; infp = stdin; if (!get_args(argc, argv)) { (void)fputs(usage, stderr); bu_exit(1, NULL); } rle_dflt_hdr.rle_file = infp; if (rle_get_setup(&rle_dflt_hdr) < 0) { fprintf(stderr, "rle-fb: Error reading setup information\n"); bu_exit(1, NULL); } if (r_debug) { fprintf(stderr, "Image bounds\n\tmin %d %d\n\tmax %d %d\n", rle_dflt_hdr.xmin, rle_dflt_hdr.ymin, rle_dflt_hdr.xmax, rle_dflt_hdr.ymax); fprintf(stderr, "%d color channels\n", rle_dflt_hdr.ncolors); fprintf(stderr, "%d color map channels\n", rle_dflt_hdr.ncmap); if (rle_dflt_hdr.alpha) fprintf(stderr, "Alpha Channel present in input, ignored.\n"); for (i=0; i < rle_dflt_hdr.ncolors; i++) fprintf(stderr, "Background channel %d = %d\n", i, rle_dflt_hdr.bg_color[i]); rle_debug(1); } if (rle_dflt_hdr.ncmap == 0) crunch = 0; /* Only interested in R, G, & B */ RLE_CLR_BIT(rle_dflt_hdr, RLE_ALPHA); for (i = 3; i < rle_dflt_hdr.ncolors; i++) RLE_CLR_BIT(rle_dflt_hdr, i); ncolors = rle_dflt_hdr.ncolors > 3 ? 3 : rle_dflt_hdr.ncolors; /* Optional switch of library to overlay mode */ if (overlay) { rle_dflt_hdr.background = 1; /* overlay */ override_background = 0; } /* Optional background color override */ if (override_background) { for (i=0; i<ncolors; i++) rle_dflt_hdr.bg_color[i] = background[i]; } file_width = rle_dflt_hdr.xmax - rle_dflt_hdr.xmin + 1; /* If screen sizes not specified, try to display rectangle part > 0 */ if (screen_width == 0) { screen_width = rle_dflt_hdr.xmax + 1; if (scr_xoff > 0) screen_width += scr_xoff; } if (screen_height == 0) { screen_height = rle_dflt_hdr.ymax + 1; if (scr_yoff > 0) screen_height += scr_yoff; } /* Incorporate command-line rectangle repositioning */ rle_dflt_hdr.xmin += scr_xoff; rle_dflt_hdr.xmax += scr_xoff; rle_dflt_hdr.ymin += scr_yoff; /* Pretend saved image origin is at 0, clip & position in fb_write call */ screen_xbase = rle_dflt_hdr.xmin; rle_dflt_hdr.xmax -= screen_xbase; rle_dflt_hdr.xmin = 0; if ((fbp = fb_open(framebuffer, screen_width, screen_height)) == FBIO_NULL) bu_exit(12, NULL); /* Honor original screen size desires, if set, unless they shrank */ if (screen_width > 0 && fb_getwidth(fbp) < screen_width) screen_width = fb_getwidth(fbp); if (screen_height > 0 && fb_getheight(fbp) < screen_height) screen_height = fb_getheight(fbp); /* Discard any scanlines which exceed screen height */ if (rle_dflt_hdr.ymax > screen_height-1) rle_dflt_hdr.ymax = screen_height-1; /* Clip left edge */ screen_xlen = rle_dflt_hdr.xmax + 1; file_skiplen = 0; if (screen_xbase < 0) { file_skiplen = -screen_xbase; screen_xbase = 0; screen_xlen -= file_skiplen; } /* Clip right edge */ if (screen_xbase + screen_xlen > screen_width) screen_xlen = screen_width - screen_xbase; if (screen_xlen <= 0 || rle_dflt_hdr.ymin > screen_height || rle_dflt_hdr.ymax < 0) { fprintf(stderr, "rle-fb: Warning: RLE image rectangle entirely off screen\n"); goto done; } scan_buf = (unsigned char *)malloc(sizeof(RGBpixel) * screen_width); for (i=0; i < ncolors; i++) rows[i] = (unsigned char *)malloc((size_t)file_width); for (; i < 3; i++) rows[i] = rows[0]; /* handle monochrome images */ /* * Import Utah color map, converting to libfb format. * Check for old format color maps, where high 8 bits * were zero, and correct them. * XXX need to handle < 3 channels of color map, by replication. */ if (rle_dflt_hdr.ncmap > 0) { int maplen = (1 << rle_dflt_hdr.cmaplen); int all = 0; for (i=0; i<256; i++) { cmap.cm_red[i] = rle_dflt_hdr.cmap[i]; cmap.cm_green[i] = rle_dflt_hdr.cmap[i+maplen]; cmap.cm_blue[i] = rle_dflt_hdr.cmap[i+2*maplen]; all |= cmap.cm_red[i] | cmap.cm_green[i] | cmap.cm_blue[i]; } if ((all & 0xFF00) == 0 && (all & 0x00FF) != 0) { /* This is an old (Edition 2) color map. * Correct by shifting it left 8 bits. */ for (i=0; i<256; i++) { cmap.cm_red[i] <<= 8; cmap.cm_green[i] <<= 8; cmap.cm_blue[i] <<= 8; } fprintf(stderr, "rle-fb: correcting for old style colormap\n"); } } if (rle_dflt_hdr.ncmap > 0 && !crunch) (void)fb_wmap(fbp, &cmap); else (void)fb_wmap(fbp, COLORMAP_NULL); /* Handle any lines below zero in y. Decode and discard. */ for (i = rle_dflt_hdr.ymin; i < 0; i++) rle_getrow(&rle_dflt_hdr, rows); for (; i <= rle_dflt_hdr.ymax; i++) { unsigned char *pp = (unsigned char *)scan_buf; rle_pixel *rp = &(rows[0][file_skiplen]); rle_pixel *gp = &(rows[1][file_skiplen]); rle_pixel *bp = &(rows[2][file_skiplen]); int j; if (overlay) { fb_read(fbp, screen_xbase, i, scan_buf, screen_xlen); for (j = 0; j < screen_xlen; j++) { *rp++ = *pp++; *gp++ = *pp++; *bp++ = *pp++; } pp = (unsigned char *)scan_buf; rp = &(rows[0][file_skiplen]); gp = &(rows[1][file_skiplen]); bp = &(rows[2][file_skiplen]); } rle_getrow(&rle_dflt_hdr, rows); /* Grumble, convert from Utah layout */ if (!crunch) { for (j = 0; j < screen_xlen; j++) { *pp++ = *rp++; *pp++ = *gp++; *pp++ = *bp++; } } else { for (j = 0; j < screen_xlen; j++) { *pp++ = cmap.cm_red[*rp++]>>8; *pp++ = cmap.cm_green[*gp++]>>8; *pp++ = cmap.cm_blue[*bp++]>>8; } } if (fb_write(fbp, screen_xbase, i, scan_buf, screen_xlen) != screen_xlen) break; } done: fb_close(fbp); return 0; }
int main(int argc, char **argv) { FBIO *fbp; unsigned char *scan_buf; int y; int cm_save_needed; outrle.rle_file = stdout; if (!get_args(argc, argv)) { (void)fputs(usage, stderr); bu_exit(1, NULL); } /* If screen size = default & file size is given, track file size */ if (screen_width == 0 && file_width > 0) screen_width = file_width; if (screen_height == 0 && file_height > 0) screen_height = file_height; if ((fbp = fb_open(framebuffer, screen_width, screen_height)) == FBIO_NULL) bu_exit(12, NULL); /* Honor original screen size desires, if set, unless they shrank */ if (screen_width == 0 || fb_getwidth(fbp) < screen_width) screen_width = fb_getwidth(fbp); if (screen_height == 0 || fb_getheight(fbp) < screen_height) screen_height = fb_getheight(fbp); /* If not specified, output file size tracks screen size */ if (file_width == 0) file_width = screen_width; if (file_height == 0) file_height = screen_height; /* Clip below and to left of (0, 0) */ if (screen_xoff < 0) { file_width += screen_xoff; screen_xoff = 0; } if (screen_yoff < 0) { file_height += screen_yoff; screen_yoff = 0; } /* Clip up and to the right */ if (screen_xoff + file_width > screen_width) file_width = screen_width - screen_xoff; if (screen_yoff + file_height > screen_height) file_height = screen_height - screen_yoff; if (file_width <= 0 || file_height <= 0) { fprintf(stderr, "fb-rle: Error: image rectangle entirely off screen\n"); bu_exit(1, NULL); } /* Read color map, see if it is linear */ cm_save_needed = 1; if (fb_rmap(fbp, &cmap) == -1) cm_save_needed = 0; if (cm_save_needed && fb_is_linear_cmap(&cmap)) cm_save_needed = 0; if (crunch && (cm_save_needed == 0)) crunch = 0; /* Convert to Utah format */ if (cm_save_needed) for (y=0; y<256; y++) { rlemap[y+0*256] = cmap.cm_red[y]; rlemap[y+1*256] = cmap.cm_green[y]; rlemap[y+2*256] = cmap.cm_blue[y]; } scan_buf = (unsigned char *)malloc(sizeof(RGBpixel) * screen_width); /* Build RLE header */ outrle.ncolors = 3; RLE_SET_BIT(outrle, RLE_RED); RLE_SET_BIT(outrle, RLE_GREEN); RLE_SET_BIT(outrle, RLE_BLUE); outrle.background = 2; /* use background */ outrle.bg_color = background; outrle.alpha = 0; /* no alpha channel */ if (cm_save_needed && !crunch) { outrle.ncmap = 3; outrle.cmaplen = 8; /* 1<<8 = 256 */ outrle.cmap = rlemap; } else { outrle.ncmap = 0; /* no color map */ outrle.cmaplen = 0; outrle.cmap = (rle_map *)0; } outrle.xmin = screen_xoff; outrle.ymin = screen_yoff; outrle.xmax = screen_xoff + file_width - 1; outrle.ymax = screen_yoff + file_height - 1; outrle.comments = (const char **)0; /* Add comments to the header file, since we have one */ if (framebuffer == (char *)0) framebuffer = fbp->if_name; snprintf(comment, COMMENT_SIZE, "encoded_from=%s", framebuffer); rle_putcom(bu_strdup(comment), &outrle); now = time(0); snprintf(comment, COMMENT_SIZE, "encoded_date=%24.24s", ctime(&now)); rle_putcom(bu_strdup(comment), &outrle); if ((who = getenv("USER")) != (char *)0) { snprintf(comment, COMMENT_SIZE, "encoded_by=%s", who); rle_putcom(bu_strdup(comment), &outrle); } # if HAVE_GETHOSTNAME gethostname(host, sizeof(host)); snprintf(comment, COMMENT_SIZE, "encoded_host=%s", host); rle_putcom(bu_strdup(comment), &outrle); # endif rle_put_setup(&outrle); rle_row_alloc(&outrle, &rows); /* Read the image a scanline at a time, and encode it */ for (y = 0; y < file_height; y++) { if (fb_read(fbp, screen_xoff, y+screen_yoff, scan_buf, file_width) == -1) { (void) fprintf(stderr, "fb-rle: read of %d pixels on line %d failed!\n", file_width, y+screen_yoff); bu_exit(1, NULL); } if (crunch) cmap_crunch((RGBpixel *)scan_buf, file_width, &cmap); /* Grumble, convert to Utah layout */ { unsigned char *pp = (unsigned char *)scan_buf; rle_pixel *rp = rows[0]; rle_pixel *gp = rows[1]; rle_pixel *bp = rows[2]; int i; for (i=0; i<file_width; i++) { *rp++ = *pp++; *gp++ = *pp++; *bp++ = *pp++; } } rle_putrow(rows, file_width, &outrle); } rle_puteof(&outrle); fb_close(fbp); fclose(outrle.rle_file); return 0; }