/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * PostScript file plugin * PostScript writing and GhostScript interfacing code * Copyright (C) 1997 Peter Kirchgessner * (email: pkirchg@aol.com, WWW: http://members.aol.com/pkirchg) * * Added controls for TextAlphaBits and GraphicsAlphaBits * George White * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* Event history: * V 0.90, PK, 28-Mar-97: Creation. * V 0.91, PK, 03-Apr-97: Clip everything outside BoundingBox. * 24-Apr-97: Multi page read support. * V 1.00, PK, 30-Apr-97: PDF support. * V 1.01, PK, 05-Oct-97: Parse rc-file. * V 1.02, GW, 09-Oct-97: Antialiasing support. * PK, 11-Oct-97: No progress bars when running non-interactive. * New procedure file_ps_load_setargs to set * load-arguments non-interactively. * If GS_OPTIONS are not set, use at least "-dSAFER" */ #define VERSIO 1.02 static char ident[] = "@(#) GIMP PostScript/PDF file-plugin v1.02 12-Oct-97"; #include #include #include #include #include #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "app/gimage.h" #include "app/gdisplay.h" #define STR_LENGTH 64 /* Load info */ typedef struct { guint resolution; /* resolution (dpi) at which to run ghostscript */ guint width, height; /* desired size (ghostscript may ignore this) */ gint use_bbox; /* 0: use width/height, 1: try to use BoundingBox */ char pages[STR_LENGTH];/* Pages to load (eg.: 1,3,5-7) */ gint pnm_type; /* 4: pbm, 5: pgm, 6: ppm, 7: automatic */ gint textalpha; /* antialiasing: 1,2, or 4 TextAlphaBits */ gint graphicsalpha; /* antialiasing: 1,2, or 4 GraphicsAlphaBits */ } PSLoadVals; typedef struct { gint run; /* run */ } PSLoadInterface; static PSLoadVals plvals = { 100, /* 100 dpi */ 826, 1170, /* default width/height (A4) */ 1, /* try to use BoundingBox */ "1-99", /* pages to load */ 6, /* use ppm (colour) */ 1, /* dont use text antialiasing */ 1 /* dont use graphics antialiasing */ }; static PSLoadInterface plint = { FALSE /* run */ }; /* Save info */ typedef struct { gdouble width, height; /* Size of image */ gdouble x_offset, y_offset; /* Offset to image on page */ gint unit_mm; /* Unit of measure (0: inch, 1: mm) */ gint keep_ratio; /* Keep aspect ratio */ gint rotate; /* Rotation (0, 90, 180, 270) */ } PSSaveVals; typedef struct { gint run; /* run */ } PSSaveInterface; static PSSaveVals psvals = { 287.0, 200.0, /* Image size (A4) */ 5.0, 5.0, /* Offset */ 1, /* Unit is mm */ 1, /* Keep edge ratio */ 90, /* Rotate */ }; static PSSaveInterface psint = { FALSE /* run */ }; /* Declare some local functions. */ static void query (void); static void run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals); static gint32 load_image (char *filename); static gint save_image (char *filename, gint32 image_ID, gint32 drawable_ID); static gint save_gray (FILE *ofp, gint32 image_ID, gint32 drawable_ID, const PSSaveVals *saveopt); static gint save_index (FILE *ofp, gint32 image_ID, gint32 drawable_ID, const PSSaveVals *saveopt); static gint save_rgb (FILE *ofp, gint32 image_ID, gint32 drawable_ID, const PSSaveVals *saveopt); static gint32 create_new_image (char *filename, guint pagenum, guint width, guint height, GImageType type, gint32 *layer_ID, GDrawable **drawable, GPixelRgn *pixel_rgn); static void check_load_vals (void); static void check_save_vals (void); static char *ftoa (char *format, double r); static gint page_in_list (char *list, guint pagenum); static gint get_bbox (char *filename, int *x0, int *y0, int *x1, int *y1); static FILE *ps_open (char *filename, const PSLoadVals *loadopt, int *llx, int* lly, int* urx, int* ury); static void ps_close (FILE *ifp); static gint32 skip_ps (FILE *ifp); static gint32 load_ps (char *filename, guint pagenum, FILE *ifp, int llx, int lly, int urx, int ury); static void save_ps_header (FILE *ofp, char *filename); static void save_ps_transform (FILE *ofp, int width, int height, int bpp); static void save_ps_trailer (FILE *ofp); /* Dialog-handling */ typedef struct { GtkWidget *dialog; GtkWidget *entry[4]; int use_bbox; int dataformat[4]; int textalphabits[3]; int graphicsalphabits[3]; } LoadDialogVals; static gint load_dialog (void); static void load_close_callback (GtkWidget *widget, gpointer data); static void load_ok_callback (GtkWidget *widget, gpointer data); static void load_toggle_update (GtkWidget *widget, gpointer data); typedef struct { GtkWidget *dialog; GtkWidget *entry[4]; int keep_ratio; int unit[2]; int rot[4]; } SaveDialogVals; static gint save_dialog (void); static void save_close_callback (GtkWidget *widget, gpointer data); static void save_ok_callback (GtkWidget *widget, gpointer data); static void save_toggle_update (GtkWidget *widget, gpointer data); static void save_mm_toggle_update (GtkWidget *widget, gpointer data); static void show_message (char *); GPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; /* The run mode */ static GRunModeType l_run_mode; MAIN () static void query (void) { static GParamDef load_args[] = { { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, { PARAM_STRING, "filename", "The name of the file to load" }, { PARAM_STRING, "raw_filename", "The name of the file to load" } }; static GParamDef load_return_vals[] = { { PARAM_IMAGE, "image", "Output image" }, }; static int nload_args = sizeof (load_args) / sizeof (load_args[0]); static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]); static GParamDef set_load_args[] = { { PARAM_INT32, "resolution", "Resolution to interprete image (dpi)" }, { PARAM_INT32, "width", "Desired width" }, { PARAM_INT32, "height", "Desired height" }, { PARAM_INT32, "check_bbox", "0: Use width/height, 1: Use BoundingBox" }, { PARAM_STRING, "pages", "Pages to load (e.g.: 1,3,5-7)" }, { PARAM_INT32, "coloring", "4: b/w, 5: grey, 6: colour image, 7: automatic" }, { PARAM_INT32, "TextAlphaBits", "1, 2, or 4" }, { PARAM_INT32, "GraphicsAlphaBits", "1, 2, or 4" } }; static int nset_load_args = sizeof (set_load_args) / sizeof (set_load_args[0]); static GParamDef save_args[] = { { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, { PARAM_IMAGE, "image", "Input image" }, { PARAM_DRAWABLE, "drawable", "Drawable to save" }, { PARAM_STRING, "filename", "The name of the file to save the image in" }, { PARAM_STRING, "raw_filename", "The name of the file to save the image in" }, { PARAM_FLOAT, "width", "Width of the image in PostScript file" }, { PARAM_FLOAT, "height", "Height of image in PostScript file" }, { PARAM_FLOAT, "x_offset", "X-offset to image from lower left corner" }, { PARAM_FLOAT, "y_offset", "Y-offset to image from lower left corner" }, { PARAM_INT32, "unit", "0: inches, 1: millimeters" }, { PARAM_INT32, "keep_ratio", "0: use width/height, 1: keep aspect ratio" }, { PARAM_INT32, "rotation", "0, 90, 180, 270" } }; static int nsave_args = sizeof (save_args) / sizeof (save_args[0]); gimp_install_procedure ("file_ps_load", "load file of PostScript/PDF file format", "load file of PostScript/PDF file format", "Peter Kirchgessner", "Peter Kirchgessner", "1997", "/PostScript", NULL, PROC_PLUG_IN, nload_args, nload_return_vals, load_args, load_return_vals); gimp_install_procedure ("file_ps_load_setargs", "set additional parameters for procedure file_ps_load", "set additional parameters for procedure file_ps_load", "Peter Kirchgessner", "Peter Kirchgessner", "1997", NULL, NULL, PROC_PLUG_IN, nset_load_args, 0, set_load_args, NULL); gimp_install_procedure ("file_ps_save", "save file in PostScript file format", "PostScript saving handles all image types except \ those with alpha channels.", "Peter Kirchgessner", "Peter Kirchgessner", "1997", "/PostScript", "RGB*, GRAY*, INDEXED*", PROC_PLUG_IN, nsave_args, 0, save_args, NULL); /* Register file plugin by plugin name and handable extensions */ gimp_register_magic_load_handler ("file_ps_load", "ps", "", "0,string,%!,0,string,%PDF"); gimp_register_save_handler ("file_ps_save", "ps", ""); } static void run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals) { static GParam values[2]; GRunModeType run_mode; GStatusType status = STATUS_SUCCESS; gint32 image_ID = -1; l_run_mode = run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = PARAM_STATUS; values[0].data.d_status = STATUS_CALLING_ERROR; if (strcmp (name, "file_ps_load") == 0) { *nreturn_vals = 2; values[1].type = PARAM_IMAGE; values[1].data.d_image = -1; switch (run_mode) { case RUN_INTERACTIVE: /* Possibly retrieve data */ gimp_get_data ("file_ps_load", &plvals); if (!load_dialog ()) return; break; case RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ if (nparams != 3) status = STATUS_CALLING_ERROR; else /* Get additional interpretation arguments */ gimp_get_data ("file_ps_load", &plvals); break; case RUN_WITH_LAST_VALS: /* Possibly retrieve data */ gimp_get_data ("file_ps_load", &plvals); break; default: break; } if (status == STATUS_SUCCESS) { check_load_vals (); image_ID = load_image (param[1].data.d_string); status = (image_ID != -1) ? STATUS_SUCCESS : STATUS_EXECUTION_ERROR; /* Store plvals data */ if (status == STATUS_SUCCESS) gimp_set_data ("file_ps_load", &plvals, sizeof (PSLoadVals)); } values[0].data.d_status = status; values[1].data.d_image = image_ID; } else if (strcmp (name, "file_ps_save") == 0) { switch (run_mode) { case RUN_INTERACTIVE: /* Possibly retrieve data */ gimp_get_data ("file_ps_save", &psvals); /* First acquire information with a dialog */ if (! save_dialog ()) return; break; case RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ if (nparams != 12) { status = STATUS_CALLING_ERROR; } else { psvals.width = param[5].data.d_float; psvals.height = param[6].data.d_float; psvals.x_offset = param[7].data.d_float; psvals.y_offset = param[8].data.d_float; psvals.unit_mm = (param[9].data.d_int32 != 0); psvals.keep_ratio = (param[10].data.d_int32 != 0); psvals.rotate = param[11].data.d_int32; } break; case RUN_WITH_LAST_VALS: /* Possibly retrieve data */ gimp_get_data ("file_ps_save", &psvals); break; default: break; } if (status == STATUS_SUCCESS) { check_save_vals (); if (save_image (param[3].data.d_string, param[1].data.d_int32, param[2].data.d_int32)) { /* Store psvals data */ gimp_set_data ("file_ps_save", &psvals, sizeof (PSSaveVals)); } else { status = STATUS_EXECUTION_ERROR; } } values[0].data.d_status = status; } else if (strcmp (name, "file_ps_load_setargs") == 0) { /* Make sure all the arguments are there! */ if (nparams != 8) { status = STATUS_CALLING_ERROR; } else { plvals.resolution = param[0].data.d_int32; plvals.width = param[1].data.d_int32; plvals.height = param[2].data.d_int32; plvals.use_bbox = param[3].data.d_int32; if (param[4].data.d_string != NULL) strncpy (plvals.pages,param[4].data.d_string,sizeof (plvals.pages)); else plvals.pages[0] = '\0'; plvals.pages[sizeof (plvals.pages) - 1] = '\0'; plvals.pnm_type = param[5].data.d_int32; plvals.textalpha = param[6].data.d_int32; plvals.graphicsalpha = param[7].data.d_int32; check_load_vals (); gimp_set_data ("file_ps_load", &plvals, sizeof (PSLoadVals)); } values[0].data.d_status = status; } } static gint32 load_image (char *filename) { gint32 image_ID, *image_list, *nl; guint page_count; FILE *ifp; char *temp,*format; int llx, lly, urx, ury; int k, n_images, max_images, max_pagenum; #ifdef PS_DEBUG printf ("load_image:\n resolution = %d\n", plvals.resolution); printf (" %dx%d pixels\n", plvals.width, plvals.height); printf (" BoundingBox: %d\n", plvals.use_bbox); printf (" Colouring: %d\n", plvals.pnm_type); printf (" TextAlphaBits: %d\n", plvals.textalpha); printf (" GraphicsAlphaBits: %d\n", plvals.graphicsalpha); #endif /* Try to see if PostScript file is available */ ifp = fopen (filename, "r"); if (ifp == NULL) { show_message ("can't open file for reading"); return (-1); } fclose (ifp); if (l_run_mode != RUN_NONINTERACTIVE) { format = "Interpreting and Loading %s:"; temp = g_malloc (strlen (format) + strlen (filename) + 5); sprintf (temp, format, filename); gimp_progress_init (temp); g_free (temp); } ifp = ps_open (filename, &plvals, &llx, &lly, &urx, &ury); if (!ifp) { show_message ("can't interprete file"); return (-1); } image_list = (gint32 *)g_malloc (10 * sizeof (gint32)); if (image_list == NULL) { show_message ("out of memory"); return (-1); } n_images = 0; max_images = 10; max_pagenum = 9999; /* Try to get the maximum pagenumber to read */ if (!page_in_list (plvals.pages, max_pagenum)) /* Is there a limit in list ? */ { max_pagenum = -1; for (temp = plvals.pages; *temp != '\0'; temp++) { if ((*temp < '0') || (*temp > '9')) continue; /* Search next digit */ sscanf (temp, "%d", &k); if (k > max_pagenum) max_pagenum = k; while ((*temp >= '0') && (*temp <= '9')) temp++; temp--; } if (max_pagenum < 1) max_pagenum = 9999; } /* Load all images */ for (page_count = 1; page_count <= max_pagenum; page_count++) { if (page_in_list (plvals.pages, page_count)) { image_ID = load_ps (filename, page_count, ifp, llx, lly, urx, ury); if (image_ID == -1) break; if (n_images == max_images) { nl = (gint32 *)g_realloc (image_list, (max_images+10)*sizeof (gint32)); if (nl == NULL) break; image_list = nl; max_images += 10; } image_list[n_images++] = image_ID; } else /* Skip an image */ { image_ID = skip_ps (ifp); if (image_ID == -1) break; } } ps_close (ifp); /* Display images in reverse order. The last will be displayed by GIMP itself*/ if (l_run_mode != RUN_NONINTERACTIVE) { for (k = n_images-1; k >= 1; k--) gimp_display_new (image_list[k]); } image_ID = (n_images > 0) ? image_list[0] : -1; g_free (image_list); return (image_ID); } static gint save_image (char *filename, gint32 image_ID, gint32 drawable_ID) { FILE* ofp; GDrawableType drawable_type; gint retval; char *temp = ident; /* Just to satisfy lint/gcc */ /* initialize */ retval = 0; drawable_type = gimp_drawable_type (drawable_ID); /* Make sure we're not saving an image with an alpha channel */ if (gimp_drawable_has_alpha (drawable_ID)) { show_message ("PostScript save cannot handle images with alpha channels"); return FALSE; } switch (drawable_type) { case INDEXED_IMAGE: case GRAY_IMAGE: case RGB_IMAGE: break; default: show_message ("cannot operate on unknown image types"); return (FALSE); break; } /* Open the output file. */ ofp = fopen (filename, "wb"); if (!ofp) { show_message ("cant open file for writing"); return (FALSE); } if (l_run_mode != RUN_NONINTERACTIVE) { temp = g_malloc (strlen (filename) + 11); sprintf (temp, "Saving %s:", filename); gimp_progress_init (temp); g_free (temp); } save_ps_header (ofp, filename); if (drawable_type == GRAY_IMAGE) retval = save_gray (ofp,image_ID, drawable_ID, &psvals); else if (drawable_type == INDEXED_IMAGE) retval = save_index (ofp,image_ID, drawable_ID, &psvals); else if (drawable_type == RGB_IMAGE) retval = save_rgb (ofp,image_ID, drawable_ID, &psvals); save_ps_trailer (ofp); fclose (ofp); return (retval); } /* Check (and correct) the load values plvals */ static void check_load_vals (void) { if (plvals.resolution < 5) plvals.resolution = 5; else if (plvals.resolution > 1440) plvals.resolution = 1440; if (plvals.width < 2) plvals.width = 2; if (plvals.height < 2) plvals.height = 2; plvals.use_bbox = (plvals.use_bbox != 0); if (plvals.pages[0] == '\0') strcpy (plvals.pages, "1-99"); if ((plvals.pnm_type < 4) || (plvals.pnm_type > 7)) plvals.pnm_type = 6; if ( (plvals.textalpha != 1) && (plvals.textalpha != 2) && (plvals.textalpha != 4)) plvals.textalpha = 1; if ( (plvals.graphicsalpha != 1) && (plvals.graphicsalpha != 2) && (plvals.graphicsalpha != 4)) plvals.graphicsalpha = 1; } /* Check (and correct) the save values psvals */ static void check_save_vals (void) {int i; i = psvals.rotate; if ((i != 0) && (i != 90) && (i != 180) && (i != 270)) psvals.rotate = 90; } /* Convert float to ascii for use in labels (cuts off trailing blanks). */ /* The pointer returned is only valid up to the next call of the function. */ static char *ftoa (char *format, double r) {static char buffer[32]; register int n; sprintf (buffer, format, r); n = strlen (buffer)-1; while ((n >= 0) && (buffer[n] == ' ')) buffer[n--] = '\0'; return (buffer); } /* Check if a page is in a given list */ static gint page_in_list (char *list, guint page_num) {char tmplist[STR_LENGTH], *c0, *c1; int state, start_num, end_num; #define READ_STARTNUM 0 #define READ_ENDNUM 1 #define CHK_LIST(a,b,c) {int low=(a),high=(b),swp; \ if ((low>0) && (high>0)) { \ if (low>high) {swp=low; low=high; high=swp;} \ if ((low<=(c))&&(high>=(c))) return (1); } } if ((list == NULL) || (*list == '\0')) return (1); strncpy (tmplist, list, STR_LENGTH); tmplist[STR_LENGTH-1] = '\0'; c0 = c1 = tmplist; while (*c1) /* Remove all whitespace and break on unsupported characters */ { if ((*c1 >= '0') && (*c1 <= '9')) { *(c0++) = *c1; } else if ((*c1 == '-') || (*c1 == ',')) { /* Try to remove double occurances of these characters */ if (c0 == tmplist) { *(c0++) = *c1; } else { if (*(c0-1) != *c1) *(c0++) = *c1; } } else break; c1++; } if (c0 == tmplist) return (1); *c0 = '\0'; /* Now we have a comma separated list like 1-4-1,-3,1- */ start_num = end_num = -1; state = READ_STARTNUM; for (c0 = tmplist; *c0 != '\0'; c0++) { switch (state) { case READ_STARTNUM: if (*c0 == ',') { if ((start_num > 0) && (start_num == (int)page_num)) return (-1); start_num = -1; } else if (*c0 == '-') { if (start_num < 0) start_num = 1; state = READ_ENDNUM; } else /* '0' - '9' */ { if (start_num < 0) start_num = 0; start_num *= 10; start_num += *c0 - '0'; } break; case READ_ENDNUM: if (*c0 == ',') { if (end_num < 0) end_num = 9999; CHK_LIST (start_num, end_num, (int)page_num); start_num = end_num = -1; state = READ_STARTNUM; } else if (*c0 == '-') { CHK_LIST (start_num, end_num, (int)page_num); start_num = end_num; end_num = -1; } else /* '0' - '9' */ { if (end_num < 0) end_num = 0; end_num *= 10; end_num += *c0 - '0'; } break; } } if (state == READ_STARTNUM) { if (start_num > 0) return (start_num == (int)page_num); } else { if (end_num < 0) end_num = 9999; CHK_LIST (start_num, end_num, (int)page_num); } return (0); #undef CHK_LIST } /* Get the BoundingBox of a PostScript file. On success, 0 is returned. */ /* On failure, -1 is returned. */ static gint get_bbox (char *filename, int *x0, int *y0, int *x1, int *y1) {char line[1024], *src; FILE *ifp; int retval = -1; ifp = fopen (filename, "rb"); if (ifp == NULL) return (-1); for (;;) { if (fgets (line, sizeof (line)-1, ifp) == NULL) break; if ((line[0] != '%') || (line[1] != '%')) continue; src = &(line[2]); while ((*src == ' ') || (*src == '\t')) src++; if (strncmp (src, "BoundingBox", 11) != 0) continue; src += 11; while ((*src == ' ') || (*src == '\t') || (*src == ':')) src++; if (strncmp (src, "(atend)", 7) == 0) continue; if (sscanf (src, "%d%d%d%d", x0, y0, x1, y1) == 4) retval = 0; break; } fclose (ifp); return (retval); } /* Open the PostScript file. On failure, NULL is returned. */ /* The filepointer returned will give a PNM-file generated */ /* by the PostScript-interpreter. */ static FILE * ps_open (char *filename, const PSLoadVals *loadopt, int *llx, int *lly, int *urx, int *ury) {char *cmd, *gs, *gs_opts, *driver, *pnmfile; FILE *fd_popen; int width, height, resolution; int x0, y0, x1, y1; int is_pdf; char TextAlphaBits[64], GraphicsAlphaBits[64], geometry[32]; resolution = loadopt->resolution; *llx = *lly = 0; width = loadopt->width; height = loadopt->height; *urx = width-1; *ury = height-1; /* Check if the file is a PDF. For PDF, we cant set geometry */ is_pdf = 0; fd_popen = fopen (filename, "r"); if (fd_popen != NULL) {char hdr[4]; fread (hdr, 1, 4, fd_popen); is_pdf = (strncmp (hdr, "%PDF", 4) == 0); fclose (fd_popen); } if ((!is_pdf) && (loadopt->use_bbox)) /* Try the BoundingBox ? */ { if ( (get_bbox (filename, &x0, &y0, &x1, &y1) == 0) && (x0 >= 0) && (y0 >= 0) && (x1 > x0) && (y1 > y0)) { *llx = (int)((x0/72.0) * resolution + 0.01); *lly = (int)((y0/72.0) * resolution + 0.01); *urx = (int)((x1/72.0) * resolution + 0.01); *ury = (int)((y1/72.0) * resolution + 0.01); width = *urx + 1; height = *ury + 1; } } if (loadopt->pnm_type == 4) driver = "pbmraw"; else if (loadopt->pnm_type == 5) driver = "pgmraw"; else if (loadopt->pnm_type == 7) driver = "pnmraw"; else driver = "ppmraw"; pnmfile = "-"; gs = getenv ("GS_PROG"); if (gs == NULL) gs = "gs"; gs_opts = getenv ("GS_OPTIONS"); if (gs_opts == NULL) gs_opts = "-dSAFER"; else gs_opts = ""; /* Ghostscript will add these options */ cmd = g_malloc (strlen (filename) + strlen (gs) + strlen (gs_opts) + strlen (pnmfile) + 256 ); if (cmd == NULL) return (NULL); TextAlphaBits[0] = GraphicsAlphaBits[0] = geometry[0] = '\0'; /* Antialiasing not available for PBM-device */ if ((loadopt->pnm_type != 4) && (loadopt->textalpha != 1)) sprintf (TextAlphaBits, "-dTextAlphaBits=%d ", (int)loadopt->textalpha); if ((loadopt->pnm_type != 4) && (loadopt->graphicsalpha != 1)) sprintf (GraphicsAlphaBits, "-dGraphicsAlphaBits=%d ", (int)loadopt->graphicsalpha); if (!is_pdf) /* For PDF, we cant set geometry */ sprintf (geometry,"-g%dx%d ", width, height); sprintf (cmd, "%s -sDEVICE=%s -r%d %s%s%s-q -dNOPAUSE %s \ -sOutputFile=%s %s -c quit", gs, driver, resolution, geometry, TextAlphaBits, GraphicsAlphaBits, gs_opts, pnmfile, filename); #ifdef PS_DEBUG printf ("Going to start ghostscript with:\n%s\n", cmd); #endif /* Start the command and use a pipe for reading the PNM-file. */ /* If someone does not like the pipe (or it does not work), just start */ /* ghostscript with a real outputfile. When ghostscript has finished, */ /* open the outputfile and return its filepointer. But be sure */ /* to close and remove the file within ps_close(). */ fd_popen = popen (cmd, "r"); g_free (cmd); return (fd_popen); } /* Close the PNM-File of the PostScript interpreter */ static void ps_close (FILE *ifp) { /* Finish reading from pipe. */ /* If a real outputfile was used, close the file and remove it. */ pclose (ifp); } /* Read the header of a raw PNM-file and return type (4-6) or -1 on failure */ static gint read_pnmraw_type (FILE *ifp, int *width, int *height, int *maxval) {register int frst, scnd, thrd; gint pnmtype; char line[1024]; /* GhostScript may write some informational messages infront of the header. */ /* We are just looking at a Px\n in the input stream. */ frst = getc (ifp); scnd = getc (ifp); thrd = getc (ifp); for (;;) { if (thrd == EOF) return (-1); if ((thrd == '\n') && (frst == 'P') && (scnd >= '1') && (scnd <= '6')) break; frst = scnd; scnd = thrd; thrd = getc (ifp); } pnmtype = scnd - '0'; /* We dont use the ASCII-versions */ if ((pnmtype >= 1) && (pnmtype <= 3)) return (-1); /* Read width/height */ for (;;) { if (fgets (line, sizeof (line)-1, ifp) == NULL) return (-1); if (line[0] != '#') break; } if (sscanf (line, "%d%d", width, height) != 2) return (-1); *maxval = 255; if (pnmtype != 4) /* Read maxval */ { for (;;) { if (fgets (line, sizeof (line)-1, ifp) == NULL) return (-1); if (line[0] != '#') break; } if (sscanf (line, "%d", maxval) != 1) return (-1); } return (pnmtype); } /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */ static gint32 create_new_image (char *filename, guint pagenum, guint width, guint height, GImageType type, gint32 *layer_ID, GDrawable **drawable, GPixelRgn *pixel_rgn) {gint32 image_ID; GDrawableType gdtype; char *tmp; if (type == GRAY) gdtype = GRAY_IMAGE; else if (type == INDEXED) gdtype = INDEXED_IMAGE; else gdtype = RGB_IMAGE; image_ID = gimp_image_new (width, height, type); if ((tmp = g_malloc (strlen (filename) + 32)) != NULL) { sprintf (tmp, "%s-pg%ld", filename, (long)pagenum); gimp_image_set_filename (image_ID, tmp); g_free (tmp); } else gimp_image_set_filename (image_ID, filename); *layer_ID = gimp_layer_new (image_ID, "Background", width, height, gdtype, 100, NORMAL_MODE); gimp_image_add_layer (image_ID, *layer_ID, 0); *drawable = gimp_drawable_get (*layer_ID); gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width, (*drawable)->height, TRUE, FALSE); return (image_ID); } /* Skip PNM image generated from PostScript file. */ /* Returns 0 on success, -1 on failure. */ static gint32 skip_ps (FILE *ifp) {register int k, c; int i, pnmtype, width, height, maxval, bpl; pnmtype = read_pnmraw_type (ifp, &width, &height, &maxval); if (pnmtype == 4) /* Portable bitmap */ bpl = (width + 7)/8; else if (pnmtype == 5) bpl = width; else if (pnmtype == 6) bpl = width*3; else return (-1); for (i = 0; i < height; i++) { k = bpl; c = EOF; while (k-- > 0) c = getc (ifp); if (c == EOF) return (-1); if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double)(i+1) / (double)height); } return (0); } /* Load PNM image generated from PostScript file */ static gint32 load_ps (char *filename, guint pagenum, FILE *ifp, int llx, int lly, int urx, int ury) {register unsigned char *dest; unsigned char *data, *bitline = NULL, *byteline = NULL, *byteptr, *temp; unsigned char bit2byte[256*8]; int width, height, tile_height, scan_lines, total_scan_lines; int image_width, image_height; int skip_left, skip_bottom; int i, j, pnmtype, maxval, bpp, nread; GImageType imagetype; gint32 layer_ID, image_ID; GPixelRgn pixel_rgn; GDrawable *drawable; int err = 0, e; pnmtype = read_pnmraw_type (ifp, &width, &height, &maxval); if ((width == urx+1) && (height == ury+1)) /* gs respected BoundingBox ? */ { skip_left = llx; skip_bottom = lly; image_width = width - skip_left; image_height = height - skip_bottom; } else { skip_left = skip_bottom = 0; image_width = width; image_height = height; } if (pnmtype == 4) /* Portable Bitmap */ { imagetype = INDEXED; nread = (width+7)/8; bpp = 1; bitline = (unsigned char *)g_malloc (nread); if (bitline == NULL) return (-1); byteline = (unsigned char *)g_malloc (nread*8); if (byteline == NULL) { g_free (bitline); return (-1); } /* Get an array for mapping 8 bits in a byte to 8 bytes */ temp = bit2byte; for (j = 0; j < 256; j++) for (i = 7; i >= 0; i--) *(temp++) = ((j & (1 << i)) != 0); } else if (pnmtype == 5) /* Portable Greymap */ { imagetype = GRAY; nread = width; bpp = 1; byteline = (unsigned char *)g_malloc (nread); if (byteline == NULL) return (-1); } else if (pnmtype == 6) /* Portable Pixmap */ { imagetype = RGB; nread = width * 3; bpp = 3; byteline = (unsigned char *)g_malloc (nread); if (byteline == NULL) return (-1); } else return (-1); image_ID = create_new_image (filename, pagenum, image_width, image_height, imagetype, &layer_ID, &drawable, &pixel_rgn); tile_height = gimp_tile_height (); data = g_malloc (tile_height * image_width * bpp); dest = data; total_scan_lines = scan_lines = 0; if (pnmtype == 4) /* Read bitimage ? Must be mapped to indexed */ {static unsigned char BWColorMap[2*3] = { 255, 255, 255, 0, 0, 0 }; gimp_image_set_cmap (image_ID, BWColorMap, 2); for (i = 0; i < height; i++) { e = (fread (bitline, 1, nread, ifp) != nread); if (total_scan_lines >= image_height) continue; err |= e; if (err) break; j = width; /* Map 1 byte of bitimage to 8 bytes of indexed image */ temp = bitline; byteptr = byteline; while (j >= 8) { memcpy (byteptr, bit2byte + *(temp++)*8, 8); byteptr += 8; j -= 8; } if (j > 0) memcpy (byteptr, bit2byte + *temp*8, j); memcpy (dest, byteline+skip_left, image_width); dest += image_width; scan_lines++; total_scan_lines++; if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double)(i+1) / (double)image_height); if ((scan_lines == tile_height) || ((i+1) == image_height)) { gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1, image_width, scan_lines); scan_lines = 0; dest = data; } if (err) break; } } else /* Read gray/rgb-image */ { for (i = 0; i < height; i++) { e = (fread (byteline, bpp, width, ifp) != width); if (total_scan_lines >= image_height) continue; err |= e; if (err) break; memcpy (dest, byteline+skip_left*bpp, image_width*bpp); dest += image_width*bpp; scan_lines++; total_scan_lines++; if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double)(i+1) / (double)image_height); if ((scan_lines == tile_height) || ((i+1) == image_height)) { gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i-scan_lines+1, image_width, scan_lines); scan_lines = 0; dest = data; } if (err) break; } } g_free (data); if (byteline) g_free (byteline); if (bitline) g_free (bitline); if (err) show_message ("EOF encountered on reading"); gimp_drawable_flush (drawable); return (err ? -1 : image_ID); } /* Write out the PostScript file header */ static void save_ps_header (FILE *ofp, char *filename) {time_t cutime = time (NULL); fprintf (ofp, "%%!PS-Adobe-3.0\n"); fprintf (ofp, "%%%%Creator: GIMP PostScript file plugin V %4.2f \ by Peter Kirchgessner\n", VERSIO); fprintf (ofp, "%%%%Title: %s\n", filename); fprintf (ofp, "%%%%CreationDate: %s", ctime (&cutime)); fprintf (ofp, "%%%%DocumentData: Clean7Bit\n"); fprintf (ofp, "%%%%Pages: 1\n"); } /* Write out transformation for image */ static void save_ps_transform (FILE *ofp, int width, int height, int bpp) {double x_offset, y_offset, x_size, y_size; double x_scale, y_scale; double width_inch, height_inch; double f1, f2, dx, dy; int xtrans, ytrans; /* initialize */ dx = 0.0; dy = 0.0; x_offset = psvals.x_offset; y_offset = psvals.y_offset; width_inch = fabs (psvals.width); height_inch = fabs (psvals.height); if (psvals.unit_mm) { x_offset /= 25.4; y_offset /= 25.4; width_inch /= 25.4; height_inch /= 25.4; } if (psvals.keep_ratio) /* Proportions to keep ? */ { /* Fit the image into the allowed size */ f1 = width_inch / width; f2 = height_inch / height; if (f1 < f2) height_inch = width_inch * (double)(height)/(double)(width); else width_inch = fabs (height_inch) * (double)(width)/(double)(height); } if ((psvals.rotate == 0) || (psvals.rotate == 180)) { x_size = width_inch; y_size = height_inch; } else { y_size = width_inch; x_size = height_inch; } fprintf (ofp, "%%%%BoundingBox: %d %d %d %d\n",(int)(x_offset*72.0), (int)(y_offset*72.0), (int)((x_offset+x_size)*72.0)+1, (int)((y_offset+y_size)*72.0)+1); fprintf (ofp, "%%%%EndComments\n"); fprintf (ofp, "%%%%BeginProlog\n"); fprintf (ofp, "%% Use own dictionary to avoid conflicts\n"); fprintf (ofp, "5 dict begin\n"); fprintf (ofp, "%%%%EndProlog\n"); fprintf (ofp, "%%%%Page: 1 1\n"); fprintf (ofp, "%% Translate for offset\n"); fprintf (ofp, "%f %f translate\n", x_offset*72.0, y_offset*72.0); /* Calculate translation to startpoint of first scanline */ switch (psvals.rotate) { case 0: dx = 0.0; dy = y_size*72.0; break; case 90: dx = dy = 0.0; x_scale = 72.0 * width_inch; y_scale = -72.0 * height_inch; break; case 180: dx = x_size*72.0; dy = 0.0; break; case 270: dx = x_size*72.0; dy = y_size*72.0; break; } if ((dx != 0.0) || (dy != 0.0)) fprintf (ofp, "%% Translate to begin of first scanline\n%f %f translate\n", dx, dy); if (psvals.rotate) fprintf (ofp, "%d rotate\n", (int)psvals.rotate); fprintf (ofp, "%f %f scale\n", 72.0*width_inch, -72.0*height_inch); /* Write the PostScript procedures to read the image */ fprintf (ofp, "%% Variable to keep one line of raster data\n"); fprintf (ofp, "/scanline %d %d mul string def\n", width, bpp); fprintf (ofp, "%% Image geometry\n%d %d 8\n", width, height); fprintf (ofp, "%% Transformation matrix\n"); xtrans = ytrans = 0; if (psvals.width < 0.0) { width = -width; xtrans = -width; } if (psvals.height < 0.0) { height = -height; ytrans = -height; } fprintf (ofp, "[ %d 0 0 %d %d %d ]\n", width, height, xtrans, ytrans); } static void save_ps_trailer (FILE *ofp) { fprintf (ofp, "%%Trailer\n"); fprintf (ofp, "end\n%%EOF\n"); } static gint save_gray (FILE *ofp, gint32 image_ID, gint32 drawable_ID, const PSSaveVals *saveopt) { int height, width, i, j; int tile_height; unsigned char *data, *src; GPixelRgn pixel_rgn; GDrawable *drawable; GDrawableType drawable_type; static char *hex = "0123456789abcdef"; drawable = gimp_drawable_get (drawable_ID); drawable_type = gimp_drawable_type (drawable_ID); width = drawable->width; height = drawable->height; tile_height = gimp_tile_height (); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE); /* allocate a buffer for retrieving information from the pixel region */ src = data = (unsigned char *)g_malloc (tile_height * width * drawable->bpp); /* Set up transformation in PostScript */ save_ps_transform (ofp, width, height, 1); /* Write read image procedure */ fprintf (ofp, "{ currentfile scanline readhexstring pop }\n"); fprintf (ofp, "image\n"); #define GET_GRAY_TILE(begin) \ {int scan_lines; \ scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \ gimp_pixel_rgn_get_rect (&pixel_rgn, begin, 0, i, width, scan_lines); \ src = begin; } for (i = 0; i < height; i++) { if ((i % tile_height) == 0) GET_GRAY_TILE (data); /* Get more data */ for (j = 0; j < width; j++) { putc (hex[(*src) >> 4], ofp); putc (hex[(*(src++)) & 0x0f], ofp); if (((j+1) % 39) == 0) putc ('\n', ofp); } putc ('\n', ofp); if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double) i / (double) height); } fprintf (ofp, "showpage\n"); g_free (data); gimp_drawable_detach (drawable); if (ferror (ofp)) { show_message ("write error occured"); return (FALSE); } return (TRUE); #undef GET_GRAY_TILE } static gint save_index (FILE *ofp, gint32 image_ID, gint32 drawable_ID, const PSSaveVals *saveopt) { int height, width, i, j; int ncols; int tile_height; unsigned char *cmap; unsigned char *data, *src; char coltab[256*6], *ct; GPixelRgn pixel_rgn; GDrawable *drawable; GDrawableType drawable_type; static char *hex = "0123456789abcdef"; static char *background = "000000"; drawable = gimp_drawable_get (drawable_ID); drawable_type = gimp_drawable_type (drawable_ID); width = drawable->width; height = drawable->height; tile_height = gimp_tile_height (); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE); /* allocate a buffer for retrieving information from the pixel region */ src = data = (unsigned char *)g_malloc (tile_height * width * drawable->bpp); cmap = gimp_image_get_cmap (image_ID, &ncols); ct = coltab; for (j = 0; j < 256; j++) { if (j >= ncols) { memcpy (ct, background, 6); ct += 6; } else { *(ct++) = (unsigned char)hex[(*cmap) >> 4]; *(ct++) = (unsigned char)hex[(*(cmap++)) & 0x0f]; *(ct++) = (unsigned char)hex[(*cmap) >> 4]; *(ct++) = (unsigned char)hex[(*(cmap++)) & 0x0f]; *(ct++) = (unsigned char)hex[(*cmap) >> 4]; *(ct++) = (unsigned char)hex[(*(cmap++)) & 0x0f]; } } /* Set up transformation in PostScript */ save_ps_transform (ofp, width, height, 3); /* Write read image procedure */ fprintf (ofp, "{ currentfile scanline readhexstring pop } false 3\n"); fprintf (ofp, "colorimage\n"); #define GET_INDEX_TILE(begin) \ {int scan_lines; \ scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \ gimp_pixel_rgn_get_rect (&pixel_rgn, begin, 0, i, width, scan_lines); \ src = begin; } for (i = 0; i < height; i++) { if ((i % tile_height) == 0) GET_INDEX_TILE (data); /* Get more data */ for (j = 0; j < width; j++) { fwrite (coltab+(*(src++))*6, 6, 1, ofp); if (((j+1) % 13) == 0) putc ('\n', ofp); } putc ('\n', ofp); if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double) i / (double) height); } fprintf (ofp, "showpage\n"); g_free (data); gimp_drawable_detach (drawable); if (ferror (ofp)) { show_message ("write error occured"); return (FALSE); } return (TRUE); #undef GET_INDEX_TILE } static gint save_rgb (FILE *ofp, gint32 image_ID, gint32 drawable_ID, const PSSaveVals *saveopt) { int height, width, tile_height; int i, j; unsigned char *data, *src; GPixelRgn pixel_rgn; GDrawable *drawable; GDrawableType drawable_type; static char *hex = "0123456789abcdef"; drawable = gimp_drawable_get (drawable_ID); drawable_type = gimp_drawable_type (drawable_ID); width = drawable->width; height = drawable->height; tile_height = gimp_tile_height (); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE); /* allocate a buffer for retrieving information from the pixel region */ src = data = (unsigned char *)g_malloc (tile_height * width * drawable->bpp); /* Set up transformation in PostScript */ save_ps_transform (ofp, width, height, 3); /* Write read image procedure */ fprintf (ofp, "{ currentfile scanline readhexstring pop } false 3\n"); fprintf (ofp, "colorimage\n"); #define GET_RGB_TILE(begin) \ {int scan_lines; \ scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \ gimp_pixel_rgn_get_rect (&pixel_rgn, begin, 0, i, width, scan_lines); \ src = begin; } for (i = 0; i < height; i++) { if ((i % tile_height) == 0) GET_RGB_TILE (data); /* Get more data */ for (j = 0; j < width; j++) { putc (hex[(*src) >> 4], ofp); /* Red */ putc (hex[(*(src++)) & 0x0f], ofp); putc (hex[(*src) >> 4], ofp); /* Green */ putc (hex[(*(src++)) & 0x0f], ofp); putc (hex[(*src) >> 4], ofp); /* Blue */ putc (hex[(*(src++)) & 0x0f], ofp); if (((j+1) % 13) == 0) putc ('\n', ofp); } putc ('\n', ofp); if ((l_run_mode != RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double) i / (double) height); } fprintf (ofp, "showpage\n"); g_free (data); gimp_drawable_detach (drawable); if (ferror (ofp)) { show_message ("write error occured"); return (FALSE); } return (TRUE); #undef GET_RGB_TILE } /* Load interface functions */ static gint load_dialog (void) { LoadDialogVals *vals; GtkWidget *button; GtkWidget *toggle; GtkWidget *frame; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *label; GtkWidget *table; GSList *group; gchar **argv; gint argc; char buffer[STR_LENGTH]; static char *label_text[] = { "Resolution:", "Width:", "Height:", "Pages:" }; static char *radio_text[] = { "b/w", "gray", "colour", "automatic" }; static char *alias_text[] = { "none", "weak", "strong" }; int j, n_prop, alias, *alpha_bits; argc = 1; argv = g_new (gchar *, 1); argv[0] = g_strdup ("load"); gtk_init (&argc, &argv); gtk_rc_parse (gimp_gtkrc ()); vals = g_malloc (sizeof (*vals)); vals->dialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (vals->dialog), "Load PostScript"); gtk_window_position (GTK_WINDOW (vals->dialog), GTK_WIN_POS_MOUSE); gtk_signal_connect (GTK_OBJECT (vals->dialog), "destroy", (GtkSignalFunc) load_close_callback, NULL); /* Action area */ button = gtk_button_new_with_label ("OK"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_signal_connect (GTK_OBJECT (button), "clicked", (GtkSignalFunc) load_ok_callback, vals); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->action_area), button, TRUE, TRUE, 0); gtk_widget_grab_default (button); gtk_widget_show (button); button = gtk_button_new_with_label ("Cancel"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (vals->dialog)); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->action_area), button, TRUE, TRUE, 0); gtk_widget_show (button); hbox = gtk_hbox_new (FALSE, 0); gtk_container_border_width (GTK_CONTAINER (hbox), 0); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->vbox), hbox, TRUE, TRUE, 0); gtk_widget_show (hbox); /* Rendering */ frame = gtk_frame_new ("Rendering"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 10); gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); vbox = gtk_vbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (vbox), 5); gtk_container_add (GTK_CONTAINER (frame), vbox); /* Resolution/Width/Height/Pages labels */ n_prop = sizeof (label_text)/sizeof (label_text[0]); table = gtk_table_new (n_prop, 2, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 5); gtk_table_set_col_spacings (GTK_TABLE (table), 5); gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); gtk_widget_show (table); for (j = 0; j < n_prop; j++) { label = gtk_label_new (label_text[j]); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, j, j+1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); } /* Resolution/Width/Height/Pages Entries */ for (j = 0; j < n_prop; j++) { vals->entry[j] = gtk_entry_new (); gtk_widget_set_usize (vals->entry[j], 80, 0); if (j == 0) sprintf (buffer, "%d", (int)plvals.resolution); else if (j == 1) sprintf (buffer, "%d", (int)plvals.width); else if (j == 2) sprintf (buffer, "%d", (int)plvals.height); else if (j == 3) strcpy (buffer, plvals.pages); gtk_entry_set_text (GTK_ENTRY (vals->entry[j]), buffer); gtk_table_attach (GTK_TABLE (table), vals->entry[j], 1, 2, j, j+1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (vals->entry[j]); } toggle = gtk_check_button_new_with_label ("try BoundingBox"); gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0); vals->use_bbox = (plvals.use_bbox != 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) load_toggle_update, &(vals->use_bbox)); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), vals->use_bbox); gtk_widget_show (toggle); gtk_widget_show (vbox); gtk_widget_show (frame); /* Colouring */ frame = gtk_frame_new ("Colouring"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 10); gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); vbox = gtk_vbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (vbox), 5); gtk_container_add (GTK_CONTAINER (frame), vbox); group = NULL; for (j = 0; j < 4; j++) { toggle = gtk_radio_button_new_with_label (group, radio_text[j]); group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); vals->dataformat[j] = (plvals.pnm_type == j+4); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) load_toggle_update, &(vals->dataformat[j])); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), vals->dataformat[j]); gtk_widget_show (toggle); } gtk_widget_show (vbox); gtk_widget_show (frame); hbox = gtk_hbox_new (FALSE, 0); gtk_container_border_width (GTK_CONTAINER (hbox), 0); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->vbox), hbox, TRUE, TRUE, 0); gtk_widget_show (hbox); for (alias = 0; alias < 2; alias++) { alpha_bits = alias ? &(vals->graphicsalphabits[0]) : &(vals->textalphabits[0]); frame = gtk_frame_new (alias ? "Graphic antialiasing":"Text antialiasing"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 10); gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0); vbox = gtk_vbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (vbox), 5); gtk_container_add (GTK_CONTAINER (frame), vbox); group = NULL; for (j = 0; j < 3; j++) { toggle = gtk_radio_button_new_with_label (group, alias_text[j]); group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); alpha_bits[j] = alias ? (plvals.graphicsalpha == (1 << j)) : (plvals.textalpha == (1 << j)); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) load_toggle_update, alpha_bits+j); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), alpha_bits[j]); gtk_widget_show (toggle); } gtk_widget_show (vbox); gtk_widget_show (frame); } gtk_widget_show (vals->dialog); gtk_main (); gdk_flush (); g_free (vals); return plint.run; } static void load_close_callback (GtkWidget *widget, gpointer data) { gtk_main_quit (); } static void load_ok_callback (GtkWidget *widget, gpointer data) {LoadDialogVals *vals = (LoadDialogVals *)data; int nelem; /* Read resolution */ plvals.resolution = atoi (gtk_entry_get_text (GTK_ENTRY (vals->entry[0]))); /* Read width */ plvals.width = atoi (gtk_entry_get_text (GTK_ENTRY (vals->entry[1]))); /* Read height */ plvals.height = atoi (gtk_entry_get_text (GTK_ENTRY (vals->entry[2]))); /* Read Pages */ nelem = sizeof (plvals.pages); strncpy (plvals.pages, gtk_entry_get_text(GTK_ENTRY (vals->entry[3])),nelem); plvals.pages[nelem-1] = '\0'; /* Read try BoundingBox */ plvals.use_bbox = (vals->use_bbox != 0); /* Read colouring */ if (vals->dataformat[0] == 1) plvals.pnm_type = 4; else if (vals->dataformat[1] == 1) plvals.pnm_type = 5; else if (vals->dataformat[3] == 1) plvals.pnm_type = 7; else plvals.pnm_type = 6; /* Read TextAlphaBits */ if (vals->textalphabits[0] == 1) plvals.textalpha = 1; else if (vals->textalphabits[1] == 1) plvals.textalpha = 2; else if (vals->textalphabits[2] == 1) plvals.textalpha = 4; else plvals.textalpha = 1; /* Read GraphicsAlphaBits */ if (vals->graphicsalphabits[0] == 1) plvals.graphicsalpha = 1; else if (vals->graphicsalphabits[1] == 1) plvals.graphicsalpha = 2; else if (vals->graphicsalphabits[2] == 1) plvals.graphicsalpha = 4; else plvals.graphicsalpha = 1; plint.run = TRUE; gtk_widget_destroy (GTK_WIDGET (vals->dialog)); } static void load_toggle_update (GtkWidget *widget, gpointer data) { int *toggle_val; toggle_val = (int *) data; *toggle_val = ((GTK_TOGGLE_BUTTON (widget)->active) != 0); } /* Save interface functions */ static gint save_dialog (void) { SaveDialogVals *vals; GtkWidget *button; GtkWidget *toggle; GtkWidget *frame, *uframe; GtkWidget *vbox, *uvbox; GtkWidget *label; GtkWidget *table; GSList *group; gchar **argv; gint argc; static char *label_text[] = { "Width:", "Height:", "X-offset:", "Y-offset:" }; static char *radio_text[] = { "0", "90", "180", "270" }; static char *unit_text[] = { "Inch", "Millimeter" }; int j; double rdata; argc = 1; argv = g_new (gchar *, 1); argv[0] = g_strdup ("save"); gtk_init (&argc, &argv); gtk_rc_parse (gimp_gtkrc ()); vals = g_malloc (sizeof (*vals)); vals->dialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (vals->dialog), "Save PostScript"); gtk_window_position (GTK_WINDOW (vals->dialog), GTK_WIN_POS_MOUSE); gtk_signal_connect (GTK_OBJECT (vals->dialog), "destroy", (GtkSignalFunc) save_close_callback, NULL); /* Action area */ button = gtk_button_new_with_label ("OK"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_signal_connect (GTK_OBJECT (button), "clicked", (GtkSignalFunc) save_ok_callback, vals); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->action_area), button, TRUE, TRUE, 0); gtk_widget_grab_default (button); gtk_widget_show (button); button = gtk_button_new_with_label ("Cancel"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (vals->dialog)); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->action_area), button, TRUE, TRUE, 0); gtk_widget_show (button); /* Image Size */ frame = gtk_frame_new ("Image Size"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 10); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->vbox), frame, FALSE, TRUE, 0); vbox = gtk_vbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (vbox), 5); gtk_container_add (GTK_CONTAINER (frame), vbox); /* Width/Height/X-/Y-offset labels */ table = gtk_table_new (4, 2, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 5); gtk_table_set_col_spacings (GTK_TABLE (table), 5); gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); gtk_widget_show (table); for (j = 0; j < 4; j++) { label = gtk_label_new (label_text[j]); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, j, j+1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); } /* Width/Height/X-off/Y-off Entries */ for (j = 0; j < 4; j++) { vals->entry[j] = gtk_entry_new (); gtk_widget_set_usize (vals->entry[j], 100, 0); if (j == 0) rdata = psvals.width; else if (j == 1) rdata = psvals.height; else if (j == 2) rdata = psvals.x_offset; else rdata = psvals.y_offset; gtk_entry_set_text (GTK_ENTRY (vals->entry[j]), ftoa ("%-8.2f", rdata)); gtk_table_attach (GTK_TABLE (table), vals->entry[j], 1, 2, j, j+1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); gtk_widget_show (vals->entry[j]); } toggle = gtk_check_button_new_with_label ("keep aspect ratio"); gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0); vals->keep_ratio = (psvals.keep_ratio != 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) save_toggle_update, &(vals->keep_ratio)); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), vals->keep_ratio); gtk_widget_show (toggle); /* Unit */ uframe = gtk_frame_new ("Unit"); gtk_frame_set_shadow_type (GTK_FRAME (uframe), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (uframe), 5); gtk_box_pack_start (GTK_BOX (vbox), uframe, FALSE, FALSE, 0); uvbox = gtk_vbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (uvbox), 5); gtk_container_add (GTK_CONTAINER (uframe), uvbox); group = NULL; for (j = 0; j < 2; j++) { toggle = gtk_radio_button_new_with_label (group, unit_text[j]); group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (uvbox), toggle, FALSE, FALSE, 0); vals->unit[j] = (psvals.unit_mm == j); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (j == 0) ? (GtkSignalFunc) save_toggle_update : (GtkSignalFunc) save_mm_toggle_update, (j == 0) ? (gpointer)(&(vals->unit[j])) : (gpointer)vals); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), vals->unit[j]); gtk_widget_show (toggle); } gtk_widget_show (uvbox); gtk_widget_show (uframe); gtk_widget_show (vbox); gtk_widget_show (frame); /* Rotation */ frame = gtk_frame_new ("Rotation"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 10); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->vbox), frame, FALSE, TRUE, 0); vbox = gtk_vbox_new (FALSE, 5); gtk_container_border_width (GTK_CONTAINER (vbox), 5); gtk_container_add (GTK_CONTAINER (frame), vbox); group = NULL; for (j = 0; j < 4; j++) { toggle = gtk_radio_button_new_with_label (group, radio_text[j]); group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); vals->rot[j] = (psvals.rotate == j*90); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) save_toggle_update, &(vals->rot[j])); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), vals->rot[j]); gtk_widget_show (toggle); } gtk_widget_show (vbox); gtk_widget_show (frame); gtk_widget_show (vals->dialog); gtk_main (); gdk_flush (); g_free (vals); return psint.run; } static void save_close_callback (GtkWidget *widget, gpointer data) { gtk_main_quit (); } static void save_ok_callback (GtkWidget *widget, gpointer data) {SaveDialogVals *vals = (SaveDialogVals *)data; double r; int k; /* Read width */ k = sscanf (gtk_entry_get_text (GTK_ENTRY (vals->entry[0])), "%lf", &r); if (k == 1) psvals.width = r; /* Read height */ k = sscanf (gtk_entry_get_text (GTK_ENTRY (vals->entry[1])), "%lf", &r); if (k == 1) psvals.height = r; /* Read x-offset */ k = sscanf (gtk_entry_get_text (GTK_ENTRY (vals->entry[2])), "%lf", &r); if (k == 1) psvals.x_offset = r; /* Read y-offset */ k = sscanf (gtk_entry_get_text (GTK_ENTRY (vals->entry[3])), "%lf", &r); if (k == 1) psvals.y_offset = r; /* Read keep aspect ratio */ psvals.keep_ratio = (vals->keep_ratio != 0); /* Read unit */ if (vals->unit[0] == 1) psvals.unit_mm = 0; else psvals.unit_mm = 1; /* Read rotation */ if (vals->rot[1] == 1) psvals.rotate = 90; else if (vals->rot[2] == 1) psvals.rotate = 180; else if (vals->rot[3] == 1) psvals.rotate = 270; else psvals.rotate = 0; psint.run = TRUE; gtk_widget_destroy (GTK_WIDGET (vals->dialog)); } static void save_toggle_update (GtkWidget *widget, gpointer data) { int *toggle_val; toggle_val = (int *) data; *toggle_val = ((GTK_TOGGLE_BUTTON (widget)->active) != 0); } static void save_mm_toggle_update (GtkWidget *widget, gpointer data) { double factor = 0.0, r; SaveDialogVals *vals = (SaveDialogVals *)data; int newval, oldval = vals->unit[1]; int mm_to_inch, inch_to_mm, j, k; newval = vals->unit[1] = ((GTK_TOGGLE_BUTTON (widget)->active) != 0); mm_to_inch = (oldval == 1) && (newval == 0); inch_to_mm = (oldval == 0) && (newval == 1); if (mm_to_inch) factor = 1.0 / 25.4; else if (inch_to_mm) factor = 25.4; if (factor != 0.0) { for (j = 0; j < 4; j++) { k = sscanf (gtk_entry_get_text (GTK_ENTRY (vals->entry[j])), "%lf", &r); if (k == 1) { gtk_entry_set_text (GTK_ENTRY(vals->entry[j]),ftoa("%-8.2f",r*factor)); gtk_widget_show (vals->entry[j]); } } } } /* Show a message. Where to show it, depends on the runmode */ static void show_message (char *message) { #ifdef Simple_Message_Box_Available /* If there would be a simple message box like the one */ /* used in ../app/interface.h, I would like to use it. */ if (l_run_mode == RUN_INTERACTIVE) gtk_message_box (message); else #endif fprintf (stderr, "ps: %s\n", message); }