/* * This file: image_f_io.c (part of the WSCRAWL program) * * This file contains the "Image File I/O" package for wscrawl (or anything * for that matter.) The format used is the standard X-Window Dump form * that the MIT client "xwd" uses. This File I/O was made possible by the * help and extensive source code of Mark Cook of Hewlett-Packard, who I * bothered endlessly to get this working. * * I tried to make this file of routines as self-contained and portable as * possible. Please feel free to use this file as is, or with modifications, * for any and all applications. -- Brian Wilson * * This file was last modified: 10/7/91 (initial port to wscrawl 2.0) */ #define TRUE 1 #define FALSE 0 #define BAD_CHOICE -1 #define NO_DUPLICATE -1 #define UNALLOCATED -1 #include #include #include #include #include XImage *read_image_from_disk(Display *disp, Window win_id, char *name_of_file, int *width, int *height, int *depth); void _swaplong (register char *bp, register unsigned int n); void _swapshort (register char *bp, register unsigned int n); /* * save_image_on_disk - this routine saves the region specified by the various * parameters out to disk in the "defacto standard" (xwd) format. * This has now been modified to take two window id's. The * first is to gather "window" information such as visual * type, etc, and the second is where the image comes from. * This is because in wscrawl 2.0, the image comes from a * Pixmap, so pixmaps are VALID for the second win_id, but * not for the first. In the simple case of getting an * image from a window, just pass the window id in twice. * * "the_colormap" can be NULL if you wish to use the default * colormap. Most times this will be the case. */ int save_image_on_disk(Display *disp, Window info_win_id, Pixmap win_id, int x, int y, int width, int height, char *name_of_file, Colormap the_colormap) { unsigned long swaptest = TRUE; XRectangle box2; XRectangle *box; FILE *out_file_ptr; XColor *colors; unsigned buffer_size; int win_name_size; int header_size; int format=ZPixmap; int ncolors, i; XWindowAttributes win_info; XImage *ImagePix; XWDFileHeader header; /* * convert to form this code understands (I got code from Mark Cook) */ box = &box2; box->x = x; box->y = y; box->width = width; box->height = height; /* * Open the file in which the image is to be stored */ if ((out_file_ptr = fopen(name_of_file, "w")) == NULL) { printf("ERROR: Could not open file %s.\n", name_of_file); return(0); } else { /* Dump the image to the specified file */ if (the_colormap == (Colormap) NULL) { the_colormap = XDefaultColormapOfScreen(XDefaultScreenOfDisplay(disp)); } if (!XGetWindowAttributes(disp, info_win_id, &win_info)) { printf("Can't get window attributes.\n"); return(0); } /* * sizeof(char) is included for the null string terminator. */ win_name_size = strlen(name_of_file) + sizeof(char); ImagePix = XGetImage(disp, win_id, box->x, box->y, box->width, box->height, AllPlanes, format); XFlush(disp); if (ImagePix == NULL) { printf("GetImage failed.\n"); return(0); } buffer_size = Image_Size(ImagePix,format);/*determines size of pixmap*/ /* * Get the RGB values for the current color cells */ if ((ncolors = Get_Colors(&colors, disp, the_colormap)) == 0) { printf("Cannot alloc memory for color structs.\n"); return(0); } XFlush(disp); header_size = sizeof(header) +win_name_size; /*Calculates header size*/ /* * Assemble the file header information */ header.header_size = (xwdval) header_size; header.file_version = (xwdval) XWD_FILE_VERSION; header.pixmap_format = (xwdval) format; header.pixmap_depth = (xwdval) ImagePix->depth; header.pixmap_width = (xwdval) ImagePix->width; header.pixmap_height = (xwdval) ImagePix->height; header.xoffset = (xwdval) ImagePix->xoffset; header.byte_order = (xwdval) ImagePix->byte_order; header.bitmap_unit = (xwdval) ImagePix->bitmap_unit; header.bitmap_bit_order = (xwdval) ImagePix->bitmap_bit_order; header.bitmap_pad = (xwdval) ImagePix->bitmap_pad; header.bits_per_pixel = (xwdval) ImagePix->bits_per_pixel; header.bytes_per_line = (xwdval) ImagePix->bytes_per_line; header.visual_class = (xwdval) win_info.visual->class; header.red_mask = (xwdval) win_info.visual->red_mask; header.green_mask = (xwdval) win_info.visual->green_mask; header.blue_mask = (xwdval) win_info.visual->blue_mask; header.bits_per_rgb = (xwdval) win_info.visual->bits_per_rgb; header.colormap_entries = (xwdval) win_info.visual->map_entries; header.ncolors = ncolors; header.window_width = (xwdval) ImagePix->width; header.window_height = (xwdval) ImagePix->height; header.window_x = (xwdval) 0; header.window_y = (xwdval) 0; header.window_bdrwidth = (xwdval) 0; if (*(char *) &swaptest) { _swaplong((char *) &header, sizeof(header)); for (i = 0; i < ncolors; i++) { _swaplong((char *) &colors[i].pixel, sizeof(long)); _swapshort((char *) &colors[i].red, 3 * sizeof(short)); } } /* * Write out the file header information */ (void) fwrite((char *)&header, sizeof(header), 1, out_file_ptr); (void) fwrite(name_of_file, win_name_size, 1, out_file_ptr); /* * Write out the color cell RGB values */ (void) fwrite((char *) colors, sizeof(XColor), ncolors, out_file_ptr); /* * Write out the buffer */ (void) fwrite(ImagePix->data, (int) buffer_size, 1, out_file_ptr); if(ncolors > 0) free(colors); /*free the color buffer*/ fclose(out_file_ptr); XFlush(disp); XDestroyImage(ImagePix); } return(1); } /* * Image_Size - this routine takes an XImage and returns it's total byte count */ int Image_Size(XImage *image, int format) { if (format != ZPixmap) return(image->bytes_per_line * image->height * image->depth); else return(image->bytes_per_line * image->height); } /* * Get_Colors - takes a pointer to an XColor struct and returns the total * number of cells in the current colormap, plus all of their * RGB values. */ Get_Colors(XColor **colors, Display *disp, Colormap the_colormap) { int i, ncolors; ncolors = DisplayCells(disp, DefaultScreen(disp)); if ((*colors = (XColor *) malloc (sizeof(XColor) * ncolors)) == NULL) return(FALSE); for (i=0; iwidth = (int) header.pixmap_width; ImagePix->height = (int) header.pixmap_height; ImagePix->xoffset = (int) header.xoffset; ImagePix->format = (int) header.pixmap_format; ImagePix->byte_order = (int) header.byte_order; ImagePix->bitmap_unit = (int) header.bitmap_unit; ImagePix->bitmap_bit_order = (int) header.bitmap_bit_order; ImagePix->bitmap_pad = (int) header.bitmap_pad; ImagePix->depth = (int) header.pixmap_depth; ImagePix->bits_per_pixel = (int) header.bits_per_pixel; ImagePix->bytes_per_line = (int) header.bytes_per_line; ImagePix->red_mask = header.red_mask; ImagePix->green_mask = header.green_mask; ImagePix->blue_mask = header.blue_mask; ImagePix->obdata = NULL; _XInitImageFuncPtrs(ImagePix); format = ImagePix->format; /* malloc memory for the RGB values from the old colormap and read * in the values */ if (ncolors = header.ncolors) { if ((colors = (XColor *) malloc(ncolors * sizeof(XColor))) == NULL) { printf("ERROR: Can't malloc space for the image cmap.\n"); if (win_name) free(win_name); if (ImagePix) XDestroyImage(ImagePix); return(0); } if (fread((char *)colors, sizeof(XColor), ncolors, in_file) != ncolors) { printf("ERROR: Unable to read cmap from imagefile.\n"); if (win_name) free(win_name); if (ImagePix) XDestroyImage(ImagePix); if (colors) free((char *) colors); return(0); } if (*(char *) &swaptest) { for (i = 0; i < ncolors; i++) { _swaplong((char *) &colors[i].pixel, sizeof(long)); _swapshort((char *) &colors[i].red, 3 * sizeof(short)); } } } buffer_size = Image_Size(ImagePix, format); /*malloc the pixel buffer*/ if ((buffer = malloc(buffer_size * sizeof(char))) == NULL) { printf("ERROR: Can't malloc the data buffer.\n"); if (win_name) free(win_name); if(ImagePix) XDestroyImage(ImagePix); if (colors) free((char *) colors); return(0); } ImagePix->data = buffer; /* * Read in the pixmap buffer */ if(fread(buffer, sizeof(char), (int)buffer_size, in_file) != buffer_size) { printf("ERROR: Unable to read pixmap from imagefile.\n"); if (win_name) free(win_name); if(ImagePix) XDestroyImage(ImagePix); if (colors) free((char *) colors); if (buffer) free((char *) buffer); return(0); } (void) fclose(in_file); /*we are done with the infile*/ *depth = ImagePix->depth; /*even if the rest fails, return the dimensions*/ *width = ImagePix->width; *height = ImagePix->height; if (win_name && (name_size > 0)) free(win_name); if (allocate_colors_and_assign_em(disp, win_id, &ImagePix, colors) != TRUE) { /* the above * converts the pixels in the xwd file over to the current colormap, * and also swaps the image to a new depth if the depth the * image was stored on disk as disagrees with the depth of the window * it is to be blasted into. This block is if that fails. */ printf("ERROR: Can't convert xwd file to usuable format.\n"); printf(" Probably because the display is a wimpy non-HP.\n"); if(ImagePix) XDestroyImage(ImagePix); if (colors) free((char *) colors); return(0); } else if (colors) free((char *) colors); *depth = ImagePix->depth; /*the depth may have changed*/ return(ImagePix); } /* * allocate_colors_and_assign_em - this function takes an XImage and it's * colormap as it was at the time the image was created, and * allocates cells in the system colormap matching those old colors * and shuffles the pixels in the image to point to our new color * cells instead of those old color cells. */ int allocate_colors_and_assign_em(Display *disp, Window win_id, XImage **image_ptr, XColor *cells) { int width, height, i, j, num_cells_in_colormap; unsigned long *opv, *npv; /*old and new pixel values*/ unsigned long tmp_pixel_value; XColor screen_in_out; XImage *diff_depth_im, *image; XWindowAttributes win_attr; int buffer_size; char *buffer; image = *image_ptr; /*for my sanity*/ height = image->height; width = image->width; /* * determine the number of cells in the colormap by taking 2 to the power * of the number of bits of depth this display has. */ for (i=0, num_cells_in_colormap=1; i<(*image_ptr)->depth; i++) num_cells_in_colormap *= 2; if (num_cells_in_colormap > 256) { printf("WARNING: This is a monster deep display image, dude. This "); printf("image\n"); printf(" will take %d mega-bytes of free memory to process.\n", ((num_cells_in_colormap * sizeof(unsigned long))/1024)/1024); } /* * set up temporary storage for the old and new pixel values */ opv = (unsigned long *) malloc(num_cells_in_colormap*sizeof(unsigned long)); npv = (unsigned long *) malloc(num_cells_in_colormap*sizeof(unsigned long)); if (!opv || !npv) { printf("ERROR: unable to malloc the temporary pixel storage.\n"); if (opv) free((char *) opv); if (npv) free((char *) npv); return(0); } /* * Each opv value is a flag indicating whether or not that pixel is * present in the image. Each npv value is it's replacement value. */ for (i=0; i= num_cells_in_colormap) { printf("ERROR: Bad pixel value at x=%d, y=%d, pixel=%ld\n", j, i, tmp_pixel_value); } else opv[tmp_pixel_value] = TRUE; } /* * For each TRUE opv allocate the colors */ for (i=0; idepth) /*cool, this is easy*/ { for (i=0; iformat, image->xoffset, NULL, width, height, image->bitmap_pad, 0); buffer_size = Image_Size(diff_depth_im, diff_depth_im->format); /*malloc pixel buffer*/ if ((buffer = malloc(buffer_size * sizeof(char))) == NULL) { printf("ERROR: Can't malloc data buffer for differing depth.\n"); return(0); } diff_depth_im->data = buffer; for (i=0; i