/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * HP-RTL file plugin * HP-RTL writing copyright (C) 1997 Peter Kirchgessner * (email: pkirchg@aol.com, WWW: http://members.aol.com/pkirchg) * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /* Event history: * V 1.00, PK, 15-May-98: Creation. */ #define VERSIO 1.00 static char dversio[] = "v1.00 15-May-98"; static char ident[] = "@(#) GIMP RTL file-plugin v1.00 15-May-98"; #include #include #include #include #include #include "gtk/gtk.h" #include "libgimp/gimp.h" /* #include "app/gimage.h" #include "app/gdisplay.h" */ /* 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) */ gint resolution; /* Resolution */ gdouble gamma; /* Gamma value */ gchar print_cmd[256]; /* Print command */ } RTLSaveVals; typedef struct { gint run; /* run */ } RTLSaveInterface; typedef struct { FILE *ofp; int encoding; /* 0: row by row, indexed by plane */ /* 1: row by row, indexed by pixel */ /* 2: row by row, direct colour by plane (not used) */ /* 3: row by row, direct colour by pixel */ /* 4: plane by plane (CMYK, not used) */ int use_hpgl2; int width, height; int resolution; int compress; /* Current compression mode */ unsigned char *uncompr_buf; unsigned char *compr_buf; } RTLDATA; static RTLSaveVals psvals = { 297.0, 210.0, /* Image size (A4) */ 0.0, 0.0, /* Offset */ 1, /* Unit is mm */ 1, /* Keep aspect ratio */ 0, /* Rotate */ 300, /* Resolution */ 1.5, /* Gamma value */ "" /* Print command */ }; static RTLSaveInterface psint = { FALSE /* run */ }; /* Declare some local functions. */ static void query (void); static void run (char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals); static void compress_packbits (int nin, unsigned char *src, int *nout, unsigned char *dst); static char *get_basename (char *filename); static gint start_print (char *print_cmd); static gint save_image (char *filename, gint32 image_ID, gint32 drawable_ID); static void get_scanrow (unsigned char *src, int width, int height, int bpp, unsigned char *dst); static void get_scancolumn (unsigned char *src, int width, int height, int bpp, unsigned char *dst); static RTLDATA *save_rtl_header (FILE *ofp, int indexed, int rtl_src_width, int rtl_src_height, gfloat rtl_dst_width, gfloat rtl_dst_height, int resolution); static void save_rtl_gray_coltab (RTLDATA *rtldata, unsigned char *gamma_map); static void save_rtl_indexed_coltab (RTLDATA *rtldata, int ncols, unsigned char *cmap, unsigned char *gamma_map); static void save_rtl_start_graphic (RTLDATA *rtldata, gfloat off_x, gfloat off_y); static void save_rtl_scanline (RTLDATA *rtldata, unsigned char *scanline, unsigned char *gamma_map); static void save_rtl_trailer (RTLDATA *rtldata); static void check_save_vals (void); static char *ftoa (char *format, double r); /* Dialog-handling */ typedef struct { GtkWidget *dialog; GtkWidget *entry[4]; int keep_ratio; int unit[2]; int rot[2]; GtkWidget *resolution_entry; GtkWidget *gamma_entry; GtkWidget *print_entry; } 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 *); static RTLDATA *rtldata_init (FILE *ofp, int encoding, int width, int height); static void rtldata_free (RTLDATA *rtldata); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; /* The run mode */ static GimpRunModeType l_run_mode; MAIN () static void query (void) { static GimpParamDef save_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" }, { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" }, { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" }, { GIMP_PDB_FLOAT, "width", "Width of the image in RTL file" }, { GIMP_PDB_FLOAT, "height", "Height of image in RTL file" }, { GIMP_PDB_FLOAT, "x_offset", "X-offset to image from upper left corner" }, { GIMP_PDB_FLOAT, "y_offset", "Y-offset to image from upper left corner\ (might be ignored by plotter)" }, { GIMP_PDB_INT32, "unit", "Unit for width/height/offset. 0: inches, 1: millimeters" }, { GIMP_PDB_INT32, "keep_ratio", "0: use width/height, 1: keep aspect ratio" }, { GIMP_PDB_INT32, "rotation", "0, 90" }, { GIMP_PDB_INT32, "resolution", "300, 360, 600, 720, ..." }, { GIMP_PDB_FLOAT, "Gamma value", "0.1,...,10.0" }, { GIMP_PDB_STRING, "print_cmd", "The print command" } }; static int nsave_args = sizeof (save_args) / sizeof (save_args[0]); gimp_install_procedure ("file_rtl_save", "save file in HP-RTL file format", "HP-RTL saving handles all image types, \ but alpha channels will be ignored. Gray and indexed images are saved with \ pixel encoding mode 1 (row by row, index by pixel), RGB images are saved \ with mode 3 (row by row, direct by pixel)", "Peter Kirchgessner ", "Peter Kirchgessner", dversio, "/RTL", "RGB*, GRAY*, INDEXED*", GIMP_PLUGIN, nsave_args, 0, save_args, NULL); /* Register file plugin by plugin name and handable extensions */ gimp_register_save_handler ("file_rtl_save", "rtl", ""); } static void run (char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpRunModeType run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; int k; l_run_mode = run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_CALLING_ERROR; if (strcmp (name, "file_rtl_save") == 0) { switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data */ gimp_get_data ("file_ps_save", &psvals); /* First acquire information with a dialog */ if (! save_dialog ()) return; break; case GIMP_RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ if (nparams != 16) { status = GIMP_PDB_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; psvals.resolution = param[12].data.d_int32; k = sizeof (psvals.print_cmd); strncpy (psvals.print_cmd, param[12].data.d_string, k); psvals.print_cmd[k-1] = '\0'; psvals.gamma = param[13].data.d_float; } break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data */ gimp_get_data ("file_ps_save", &psvals); break; default: break; } if (status == GIMP_PDB_SUCCESS) { check_save_vals (); if (save_image (param[3].data.d_string, param[1].data.d_int32, param[2].data.d_int32) < 0) { status = GIMP_PDB_EXECUTION_ERROR; } else { /* Store psvals data */ gimp_set_data ("file_ps_save", &psvals, sizeof (RTLSaveVals)); /* Try to start print command */ start_print ((char *)param[3].data.d_string); } } values[0].data.d_status = status; } } static void compress_packbits (int nin, unsigned char *src, int *nout, unsigned char *dst) {register unsigned char c; int nrepeat, nliteral; unsigned char *run_start; unsigned char *start_dst = dst; unsigned char *last_literal = NULL; for (;;) { if (nin <= 0) break; run_start = src; c = *run_start; /* Search repeat bytes */ if ((nin > 1) && (c == src[1])) { nrepeat = 1; nin -= 2; src += 2; while ((nin > 0) && (c == *src)) { nrepeat++; src++; nin--; if (nrepeat == 127) break; /* Maximum repeat */ } /* Add two-byte repeat to last literal run ? */ if ( (nrepeat == 1) && (last_literal != NULL) && (((*last_literal)+1)+2 <= 128)) { *last_literal += 2; *(dst++) = c; *(dst++) = c; continue; } /* Add repeat run */ *(dst++) = (unsigned char)((-nrepeat) & 0xff); *(dst++) = c; last_literal = NULL; continue; } /* Search literal bytes */ nliteral = 1; nin--; src++; for (;;) { if (nin <= 0) break; if ((nin >= 2) && (src[0] == src[1])) /* A two byte repeat ? */ break; nliteral++; nin--; src++; if (nliteral == 128) break; /* Maximum literal run */ } /* Could be added to last literal run ? */ if ((last_literal != NULL) && (((*last_literal)+1)+nliteral <= 128)) { *last_literal += nliteral; } else { last_literal = dst; *(dst++) = (unsigned char)(nliteral-1); } while (nliteral-- > 0) *(dst++) = *(run_start++); } *nout = dst - start_dst; } static char * str_replace (char *src, char *pattern, char *replace) {int k, patlen = 0; char *s, *dst; char *retval; if (src == NULL) return NULL; /* Count number of replacements */ k = 0; if ((pattern != NULL) && (*pattern != '\0')) { patlen = strlen (pattern); s = src; for (;;) { s = strstr (s, pattern); if (s == NULL) break; k++; s += patlen; } } if (k == 0) return g_strdup (src); k = strlen (src) + k*(strlen (replace) - patlen)+ 1; retval = dst = g_malloc (k); if (dst == NULL) return NULL; memset (dst, 0, k); for (;;) { s = strstr (src, pattern); if (s == NULL) /* No more patterns */ { strcpy (dst, src); /* Copy the rest */ break; } strncpy (dst, src, s - src); /* Copy up to pattern */ dst += s - src; /* Go to end of string */ strcpy (dst, replace); /* Copy replacement */ dst += strlen (replace); /* Go to end of string */ src = s + patlen; /* Look for next pattern */ } return retval; } static char * get_basename (char *filename) {char *s = NULL; while (*filename) { if ((filename[0] == '/') && (filename[1] != '\0')) s = filename+1; filename++; } return (s == NULL) ? filename : s; } static gint start_print (char *filename) {char *print_cmd, *s; int retval = -1; print_cmd = psvals.print_cmd; while ((*print_cmd == ' ') || (*print_cmd == '\t')) print_cmd++; if (*print_cmd == '\0') return 0; if ((strstr (print_cmd, "#F") == NULL) && (strstr (print_cmd, "#B") == NULL)) { s = g_malloc (strlen (print_cmd) + 1 + strlen (filename) + 1); if (s != NULL) sprintf (s, "%s %s", print_cmd, filename); print_cmd = s; } else { s = str_replace (print_cmd, "#F", (char *)filename); print_cmd = str_replace (s, "#B", get_basename ((char *)filename)); if (s) g_free (s); } if (print_cmd) { retval = system (print_cmd); g_free (print_cmd); } return retval; } static gint save_image (char *filename, gint32 image_ID, gint32 drawable_ID) { FILE* ofp; GimpImageType drawable_type; GimpDrawable *drawable = NULL; GimpPixelRgn pixel_rgn; RTLDATA *rtldata = NULL; gint retval = -1, indexed = 0; gint image_width, image_height, rtl_src_width, rtl_src_height; gfloat rtl_dst_width, rtl_dst_height, scale_x, scale_y; gfloat off_x, off_y; unsigned char *data = NULL, *src = NULL; unsigned char *scanline = NULL; static unsigned char gamma_map[256]; char *temp = ident; /* Just to satisfy lint/gcc */ int tile_height, tile_width, num_scanlines = 0; int i; /* initialize */ retval = 0; drawable_type = gimp_drawable_type (drawable_ID); switch (drawable_type) { case GIMP_INDEXED_IMAGE: case GIMP_INDEXEDA_IMAGE: case GIMP_GRAY_IMAGE: case GIMP_GRAYA_IMAGE: indexed = 1; break; case GIMP_RGB_IMAGE: case GIMP_RGBA_IMAGE: indexed = 0; break; default: show_message ("cannot operate on unknown image types"); return (-1); break; } /* Open the output file. */ ofp = fopen (filename, "wb"); if (!ofp) { show_message ("cant open file for writing"); return (-1); } if (l_run_mode != GIMP_RUN_NONINTERACTIVE) { temp = g_malloc (strlen (filename) + 11); sprintf (temp, "Saving %s:", filename); gimp_progress_init (temp); g_free (temp); } tile_height = gimp_tile_height (); tile_width = gimp_tile_width (); drawable = gimp_drawable_get (drawable_ID); image_width = drawable->width; image_height = drawable->height; gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, image_width, image_height, FALSE, FALSE); if (psvals.rotate == 0) { rtl_src_width = image_width, rtl_src_height = image_height; rtl_dst_width = psvals.width, rtl_dst_height = psvals.height; scanline = (unsigned char *)g_malloc (image_width*drawable->bpp); if (scanline == NULL) goto err_return; data = (unsigned char *)g_malloc (tile_height*image_width*drawable->bpp); } else { rtl_src_width = image_height, rtl_src_height = image_width; rtl_dst_width = psvals.height, rtl_dst_height = psvals.width; scanline = (unsigned char *)g_malloc (image_height*drawable->bpp); if (scanline == NULL) goto err_return; data = (unsigned char *)g_malloc (tile_width*image_height*drawable->bpp); } if (data == NULL) goto err_return; off_x = psvals.x_offset; off_y = psvals.y_offset; if (psvals.keep_ratio) { scale_x = rtl_dst_width / rtl_src_width; scale_y = rtl_dst_height / rtl_src_height; if (scale_x < scale_y) rtl_dst_height = scale_x * rtl_src_height; else rtl_dst_width = scale_y * rtl_src_width; } if (psvals.unit_mm) { rtl_dst_width /= 25.4; rtl_dst_height /= 25.4; off_x /= 25.4; off_y /= 25.4; } /* Set up gamma map */ for (i = 0; i < 256; i++) gamma_map[i] = 255.0 * pow (i / 255.0, 1.0 / psvals.gamma); /* Start writing RTL header */ rtldata = save_rtl_header (ofp, indexed, rtl_src_width, rtl_src_height, rtl_dst_width, rtl_dst_height, (int)psvals.resolution); if (rtldata == NULL) goto err_return; /* Write colour table if necessray */ if ((drawable_type == GIMP_INDEXED_IMAGE) || (drawable_type == GIMP_INDEXEDA_IMAGE)) {unsigned char *cmap; int ncols; cmap = gimp_image_get_cmap (image_ID, &ncols); save_rtl_indexed_coltab (rtldata, ncols, cmap, gamma_map); } else if ((drawable_type == GIMP_GRAY_IMAGE) || (drawable_type == GIMP_GRAYA_IMAGE)) { save_rtl_gray_coltab (rtldata, gamma_map); } save_rtl_start_graphic (rtldata, off_x, off_y); if (feof (ofp)) goto err_return; if (psvals.rotate == 0) { src = data; for (i = 0; i < image_height; i++) { if ((i % tile_height) == 0) /* Get a new tile */ { num_scanlines = (i+tile_height-1 < image_height) ? tile_height : (image_height-i); gimp_pixel_rgn_get_rect (&pixel_rgn,data,0,i,image_width,num_scanlines); src = data; } /* Get a scanline */ get_scanrow (src, image_width, num_scanlines, drawable->bpp, scanline); save_rtl_scanline (rtldata, scanline, gamma_map); if (feof (ofp)) goto err_return; src += image_width * drawable->bpp; if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double) i / (double) image_height); } } else /* Rotate 90. Simulate */ { src = data; for (i = 0; i < image_width; i++) { if ((i % tile_width) == 0) /* Get a new tile */ { num_scanlines = (i+tile_width-1 < image_width) ? tile_width : (image_width-i); gimp_pixel_rgn_get_rect (&pixel_rgn,data,i,0,num_scanlines,image_height); src = data; } /* Rotate a scanline */ get_scancolumn (src,num_scanlines,image_height,drawable->bpp,scanline); save_rtl_scanline (rtldata, scanline, gamma_map); if (feof (ofp)) goto err_return; src += drawable->bpp; if ((l_run_mode != GIMP_RUN_NONINTERACTIVE) && ((i % 20) == 0)) gimp_progress_update ((double) i / (double) image_height); } } save_rtl_trailer (rtldata); if (feof (ofp)) goto err_return; retval = 0; err_return: gimp_drawable_detach (drawable); if (rtldata) rtldata_free (rtldata); if (data) g_free (data); if (scanline) g_free (scanline); fclose (ofp); return (retval); } /* Check (and correct) the save values psvals */ static void check_save_vals (void) {int i; if (psvals.width <= 0.0) psvals.width = 297.0; if (psvals.height <= 0.0) psvals.height = 210.0; if (psvals.x_offset <= 0.0) psvals.x_offset = 0.0; if (psvals.y_offset <= 0.0) psvals.y_offset = 0.0; i = psvals.rotate; if ((i != 0) && (i != 90)) psvals.rotate = 0; if (psvals.resolution < 25) psvals.resolution = 25; if (psvals.gamma < 0.1) psvals.gamma = 0.1; else if (psvals.gamma > 10.0) psvals.gamma = 10.0; } /* 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); } static void get_scanrow (register unsigned char *src, register int width, int height, int bpp, register unsigned char *dst) {int nbsl = width*bpp; if ((width <= 0) || (bpp <= 0)) return; if ((bpp == 3) || (bpp == 1)) /* RGB, INDEXED, GRAY */ { memcpy ((char *)dst, (char *)src, nbsl); } else if (bpp > 3) /* RGBA */ { while (width--) { *(dst++) = src[0]; *(dst++) = src[1]; *(dst++) = src[2]; src += bpp; } } else /* INDEXEDA, GRAYA */ { while (width--) { *(dst++) = *src; src += bpp; } } } static void get_scancolumn (register unsigned char *src, int width, register int height, int bpp, register unsigned char *dst) {int nbsl = width*bpp; if ((height <= 0) || (bpp <= 0)) return; src += nbsl * (height - 1); /* Position to last pixel in column */ if (bpp >= 3) /* RGB and RGBA */ { while (height--) { *(dst++) = src[0]; *(dst++) = src[1]; *(dst++) = src[2]; src -= nbsl; } } else /* INDEXED, INDEXEDA, GRAY, GRAYA */ { while (height--) { *(dst++) = *src; src -= nbsl; } } } /* Write the header of an RTL file */ static RTLDATA * save_rtl_header (FILE *ofp, int indexed, int rtl_src_width, int rtl_src_height, gfloat rtl_dst_width, gfloat rtl_dst_height, int resolution) {int encoding; RTLDATA *rtldata; encoding = indexed ? 1 : 3; rtldata = rtldata_init (ofp, encoding, rtl_src_width, rtl_src_height); if (rtldata == NULL) return NULL; rtldata->resolution = resolution; /* Reset, Enter RTL, No negative motion */ fprintf (ofp, "\033E\033%%1A\033&a1N"); /* Configure image data */ if (encoding == 1) fwrite ("\033*v6W\0\01\010\010\010\010", 1, 11, ofp); else fwrite ("\033*v6W\0\03\01\010\010\010", 1, 11, ofp); /* Source raster width/height */ fprintf (ofp, "\033*r%dS\033*r%dT", rtl_src_width, rtl_src_height); /* Destination raster width/height */ fprintf (ofp, "\033*t%dH\033*t%dV", (int)(rtl_dst_width * 720.0), (int)(rtl_dst_height * 720.0)); /* Switch off compression */ rtldata->compress = 0; fprintf (ofp, "\033*b%dM", rtldata->compress); if (feof (ofp)) { rtldata_free (rtldata); rtldata = NULL; } return rtldata; } static void save_rtl_gray_coltab (RTLDATA *rtldata, unsigned char *gamma_map) {int k, gk; for (k = 0; k < 256; k++) { gk = gamma_map[k]; /* Set red/green/blue parameter and assign color index */ fprintf (rtldata->ofp, "\033*v%da%db%dc%dI", gk, gk, gk, k); } } static void save_rtl_indexed_coltab (RTLDATA *rtldata, int ncols, unsigned char *cmap, unsigned char *gamma_map) {int k; for (k = 0; k < ncols; k++) { /* Set red/green/blue parameter and assign color index */ fprintf (rtldata->ofp, "\033*v%da%db%dc%dI", gamma_map[cmap[0]], gamma_map[cmap[1]], gamma_map[cmap[2]], k); cmap += 3; } } static void save_rtl_start_graphic (RTLDATA *rtldata, gfloat off_x, gfloat off_y) { /* Set resolution */ fprintf (rtldata->ofp, "\033*t%dR", rtldata->resolution); /* Position CAP horizontally (decipoints) */ fprintf (rtldata->ofp, "\033&a+%dH", (int)(off_x * 720.0)); /* Position CAP vertically (pixels) (might be ignored by plotter) */ fprintf (rtldata->ofp, "\033*p+%dY", (int)(off_y * rtldata->resolution)); /* Start raster graphics with scaling */ fprintf (rtldata->ofp, "\033*r3A"); } static void save_rtl_scanline (RTLDATA *rtldata, unsigned char *scanline, unsigned char *gamma_map) {register int k; register unsigned char *rgb; int n_uncompressed, n_compressed; int use_compress; unsigned char *uncompr_buf; n_uncompressed = rtldata->width; uncompr_buf = scanline; if (rtldata->encoding == 3) /* direct colour by pixel */ { /* Apply gamma-map to direct colour */ rgb = rtldata->uncompr_buf; k = rtldata->width; while (k--) { *(rgb++) = gamma_map[*(scanline++)]; *(rgb++) = gamma_map[*(scanline++)]; *(rgb++) = gamma_map[*(scanline++)]; } n_uncompressed = rtldata->width * 3; uncompr_buf = rtldata->uncompr_buf; } if (rtldata->compr_buf == NULL) /* No memory for compression ? */ { fprintf (rtldata->ofp, "\033*b%dW", n_uncompressed); fwrite ((char *)uncompr_buf, 1, n_uncompressed, rtldata->ofp); return; } /* Try compression */ compress_packbits (n_uncompressed, uncompr_buf, &n_compressed, rtldata->compr_buf); if (rtldata->compress == 0) use_compress = (n_compressed+6 < n_uncompressed); else use_compress = (n_compressed < n_uncompressed+6); if (use_compress) { if (rtldata->compress != 2) { fprintf (rtldata->ofp, "\033*b2M"); rtldata->compress = 2; } fprintf (rtldata->ofp, "\033*b%dW", n_compressed); fwrite ((char *)rtldata->compr_buf, 1, n_compressed, rtldata->ofp); } else /* No compression */ { if (rtldata->compress != 0) { fprintf (rtldata->ofp, "\033*b0M"); rtldata->compress = 0; } fprintf (rtldata->ofp, "\033*b%dW", n_uncompressed); fwrite ((char *)uncompr_buf, 1, n_uncompressed, rtldata->ofp); } } static void save_rtl_trailer (RTLDATA *rtldata) { fprintf (rtldata->ofp, "\033*rC\033E"); } /* Save interface functions */ static gint save_dialog (void) { SaveDialogVals *vals; GtkWidget *button; GtkWidget *toggle; GtkWidget *frame, *uframe; GtkWidget *hbox, *uhbox, *vbox, *uvbox; GtkWidget *main_vbox[2]; 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" }; static char *unit_text[] = { "Inch", "Millimeter" }; char buffer[128]; 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 RTL"); 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); /* Main hbox */ 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, FALSE, TRUE, 0); main_vbox[0] = main_vbox[1] = NULL; for (j = 0; j < sizeof (main_vbox) / sizeof (main_vbox[0]); j++) { main_vbox[j] = gtk_vbox_new (FALSE, 0); gtk_container_border_width (GTK_CONTAINER (main_vbox[j]), 0); gtk_box_pack_start (GTK_BOX (hbox), main_vbox[j], TRUE, TRUE, 0); } /* 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), 5); gtk_box_pack_start (GTK_BOX (main_vbox[0]), 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], 50, 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), 5); gtk_box_pack_start (GTK_BOX (main_vbox[1]), 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 < 2; 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); /* Device resolution */ frame = gtk_frame_new ("Device"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 5); gtk_box_pack_start (GTK_BOX (main_vbox[1]), frame, TRUE, TRUE, 0); uhbox = gtk_hbox_new (FALSE, 0); gtk_container_border_width (GTK_CONTAINER (uhbox), 5); gtk_container_add (GTK_CONTAINER (frame), uhbox); /* Resolution label */ label = gtk_label_new ("Resolution (dpi): "); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (uhbox), label, TRUE, TRUE, 0); /* Resolution entry */ vals->resolution_entry = gtk_entry_new (); gtk_widget_set_usize (vals->resolution_entry, 40, 0); gtk_box_pack_start (GTK_BOX (uhbox), vals->resolution_entry, TRUE, TRUE, 0); sprintf (buffer, "%d", psvals.resolution); gtk_entry_set_text (GTK_ENTRY (vals->resolution_entry), buffer); gtk_widget_show (label); gtk_widget_show (vals->resolution_entry); gtk_widget_show (uhbox); gtk_widget_show (frame); /* Brightness */ frame = gtk_frame_new ("Brightness"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 5); gtk_box_pack_start (GTK_BOX (main_vbox[1]), frame, TRUE, TRUE, 0); uhbox = gtk_hbox_new (FALSE, 0); gtk_container_border_width (GTK_CONTAINER (uhbox), 5); gtk_container_add (GTK_CONTAINER (frame), uhbox); /* Gamma label */ label = gtk_label_new ("Gamma: "); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (uhbox), label, TRUE, TRUE, 0); /* Gamma entry */ vals->gamma_entry = gtk_entry_new (); gtk_widget_set_usize (vals->gamma_entry, 40, 0); gtk_box_pack_start (GTK_BOX (uhbox), vals->gamma_entry, TRUE, TRUE, 0); gtk_entry_set_text (GTK_ENTRY (vals->gamma_entry), ftoa ("%-8.2f", psvals.gamma)); gtk_widget_show (label); gtk_widget_show (vals->gamma_entry); gtk_widget_show (uhbox); gtk_widget_show (frame); /* Print command */ frame = gtk_frame_new ("Print command"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 5); gtk_box_pack_start (GTK_BOX (main_vbox[1]), frame, TRUE, TRUE, 0); uhbox = gtk_hbox_new (FALSE, 0); gtk_container_border_width (GTK_CONTAINER (uhbox), 5); gtk_container_add (GTK_CONTAINER (frame), uhbox); vals->print_entry = gtk_entry_new (); gtk_widget_set_usize (vals->print_entry, 80, 0); gtk_box_pack_start (GTK_BOX (uhbox), vals->print_entry, TRUE, TRUE, 0); gtk_entry_set_text (GTK_ENTRY (vals->print_entry), psvals.print_cmd); gtk_widget_show (vals->print_entry); gtk_widget_show (uhbox); gtk_widget_show (frame); for (j = 0; j < sizeof (main_vbox) / sizeof (main_vbox[0]); j++) gtk_widget_show (main_vbox[j]); gtk_widget_show (hbox); 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, i; /* 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 psvals.rotate = 0; /* Read resolution */ k = sscanf (gtk_entry_get_text (GTK_ENTRY (vals->resolution_entry)),"%d",&i); if (k == 1) psvals.resolution = i; /* Read gamma */ k = sscanf (gtk_entry_get_text (GTK_ENTRY (vals->gamma_entry)), "%lf", &r); if (k == 1) psvals.gamma = r; /* Read print command */ strncpy (psvals.print_cmd, gtk_entry_get_text (GTK_ENTRY (vals->print_entry)), sizeof (psvals.print_cmd)); psvals.print_cmd[sizeof (psvals.print_cmd)-1] = '\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, "rtl: %s\n", message); } static RTLDATA * rtldata_init (FILE *ofp, int encoding, int width, int height) {RTLDATA *rtldata; int bpp; rtldata = (RTLDATA *)g_malloc (sizeof (RTLDATA)); if (rtldata == NULL) return NULL; rtldata->ofp = ofp; rtldata->width = width; rtldata->height = height; rtldata->encoding = encoding; rtldata->use_hpgl2 = 0; rtldata->compress = 0; rtldata->uncompr_buf = rtldata->compr_buf = NULL; bpp = (encoding > 1) ? 3 : 1; rtldata->uncompr_buf = (unsigned char *)g_malloc (width * bpp); if (rtldata->uncompr_buf == NULL) { rtldata_free (rtldata); return NULL; } rtldata->compr_buf = (unsigned char *)g_malloc ((int)((width*bpp) * 1.2) + 5); return rtldata; } static void rtldata_free (RTLDATA *rtldata) { if (rtldata == NULL) return; if (rtldata->uncompr_buf) { g_free (rtldata->uncompr_buf); rtldata->uncompr_buf = NULL; } if (rtldata->compr_buf) { g_free (rtldata->compr_buf); rtldata->compr_buf = NULL; } g_free (rtldata); }