From fcd7956d3b5c0b7af5206e2e30336c936f63cc93 Mon Sep 17 00:00:00 2001 From: Joaquim Date: Wed, 27 Mar 2024 15:16:35 +0000 Subject: [PATCH 01/16] Add option to not create a temporary EPS file but instead edit the original PS. --- src/psconvert.c | 231 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 165 insertions(+), 66 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index d0b168675f5..70b9765221b 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -41,7 +41,7 @@ #define THIS_MODULE_NEEDS "" #define THIS_MODULE_OPTIONS "-V" -#ifdef WIN32 /* Special for Windows */ +#ifdef _WIN32 /* Special for Windows */ # include # include # define getpid _getpid @@ -193,9 +193,12 @@ struct PSCONVERT_CTRL { struct PSCONVERT_Z { /* -Z */ bool active; } Z; + struct PSCONVERT_O { /* -0 */ + bool active; + } O; }; -#ifdef WIN32 /* Special for Windows */ +#ifdef _WIN32 /* Special for Windows */ GMT_LOCAL int psconvert_ghostbuster(struct GMTAPI_CTRL *API, struct PSCONVERT_CTRL *C); #else /* Abstraction to get popen to do bidirectional read/write */ @@ -610,7 +613,7 @@ static void *New_Ctrl (struct GMT_CTRL *GMT) { /* Allocate and initialize a new perror("Error Description while accessing the GS executable:"); } if (!found_gs) { /* Shit. But try still the generic non-Julian paths */ - #ifdef WIN32 + #ifdef _WIN32 if (psconvert_ghostbuster(GMT->parent, C) != GMT_NOERROR) /* Try first to find the gspath from registry */ C->G.file = strdup (GMT_GS_EXECUTABLE); /* Fall back to this default and expect a miracle */ #else @@ -618,7 +621,7 @@ static void *New_Ctrl (struct GMT_CTRL *GMT) { /* Allocate and initialize a new #endif } #else - #ifdef WIN32 + #ifdef _WIN32 if (psconvert_ghostbuster(GMT->parent, C) != GMT_NOERROR) /* Try first to find the gspath from registry */ C->G.file = strdup (GMT_GS_EXECUTABLE); /* Fall back to this default and expect a miracle */ #else @@ -667,7 +670,7 @@ static int usage (struct GMTAPI_CTRL *API, int level) { GMT_Usage (API, 0, "usage: %s [-A[+r][+u]] [-C] [-D] [-E] " "[-F] [-G] [-H] [-I[+m][+s[m][/]][+S]] [-L] [-Mb|f] " "[-N[+f][+g][+k][+p[]]] [-P] [-Q[g|p|t]1|2|4] [-S] [-Tb|e|E|f|F|g|G|j|m|s|t[+m][+q]] [%s] " - "[-W[+a[]][+c][+f/][+g][+k][+l/][+n][+o][+t][+u<URL>]]%s " + "[-W[+a<mode>[<alt>]][+c][+f<minfade>/<maxfade>][+g][+k][+l<lodmin>/<lodmax>][+n<name>][+o<folder>][+t<title>][+u<URL>]]%s [-!]" "[%s]\n", name, GMT_V_OPT, Z, GMT_PAR_OPT); if (level == GMT_SYNOPSIS) return (GMT_MODULE_SYNOPSIS); @@ -704,8 +707,8 @@ static int usage (struct GMTAPI_CTRL *API, int level) { "Under Windows, Ghostscript path is fished from the registry. " "If this fails you can still add the GS path to system's path " "or give the full path here, e.g., " -#ifdef WIN32 - "-Gc:\\programs\\gs\\gs9.27\\bin\\gswin64c)."); +#ifdef _WIN32 + "-Gc:\\programs\\gs\\bin\\gswin64c)."); #else "-G/some/unusual/dir/bin/gs)."); #endif @@ -813,6 +816,7 @@ static int usage (struct GMTAPI_CTRL *API, int level) { "Escape any +? modifier inside strings with \\."); if (API->GMT->current.setting.run_mode == GMT_CLASSIC) GMT_Usage (API, 1, "\n-Z Remove input PostScript file(s) after successful conversion."); + GMT_Usage (API, 1, "\n-! Modify the input PS file instead of creating a temp EPS. Some options like -Ng will disable it."); GMT_Option (API, "."); return (GMT_MODULE_USAGE); @@ -823,7 +827,7 @@ static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_ * Any GMT common options will override values set previously by other commands. * It also replaces any file names specified as input or output with the data ID * returned when registering these sources/destinations with the API. - */ + */ unsigned int n_errors = 0, mode; int j = 0; @@ -1008,6 +1012,10 @@ static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_ } break; + case '!': /* Modify input PS instead of creating a new temp EPS one */ + Ctrl->O.active = true; + break; + default: /* Report bad options */ n_errors += gmt_default_option_error (GMT, opt); break; @@ -1078,19 +1086,17 @@ static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_ return (n_errors ? GMT_PARSE_ERROR : GMT_NOERROR); } -GMT_LOCAL int64_t psconvert_file_line_reader (struct GMT_CTRL *GMT, char **L, size_t *size, FILE *fp, char *notused1, uint64_t *notused2) { +GMT_LOCAL int64_t psconvert_file_line_reader(struct GMT_CTRL *GMT, char **L, size_t *size, FILE *fp) { /* psconvert_file_line_reader gets the next logical record from file pointer fp and passes it back via L. * We use this function since PS files may be shitty and contain a mixture of \r or \n * to indicate end of a logical record. * all_PS and pos are not used. * Empty lines are suppressed. * If the last end-of-line is missing, the last line is still produced with an end-of-line. - */ + */ int c; int64_t out = 0; char *line = *L; - if (notused1 == NULL){}; /* Just to shut up a compiler warning of "unreferenced formal parameter" */ - if (notused2 == NULL){}; /* "" */ while ((c = fgetc (fp)) > 0) { /* Keep reading until End-Of-File */ if (c == '\r' || c == '\n') { /* Got logical end of record */ if (!out) continue; /* Nothing in buffer ... skip */ @@ -1109,13 +1115,8 @@ GMT_LOCAL int64_t psconvert_file_line_reader (struct GMT_CTRL *GMT, char **L, si return out; /* Return number of characters in L. The next call to the routine will return EOF. */ } -GMT_LOCAL void psconvert_file_rewind (FILE *fp, uint64_t *notused) { /* Rewinds to start of file */ - if (notused == NULL){}; /* Just to shut up a compiler warning of "unreferenced formal parameter" */ - rewind (fp); -} - -#define bailout(code) {gmt_M_free_options (mode); return (code);} -#define Return(code) {Free_Ctrl (GMT, Ctrl); gmt_end_module (GMT, GMT_cpy); bailout (code);} +#define bailout(code) {gmt_M_free_options(mode); return (code);} +#define Return(code) {gmt_M_toc(GMT); Free_Ctrl(GMT, Ctrl); gmt_end_module(GMT, GMT_cpy); bailout(code);} GMT_LOCAL inline char *psconvert_alpha_bits (struct PSCONVERT_CTRL *Ctrl) { /* return alpha bits which are valid for the selected driver */ @@ -1623,11 +1624,13 @@ GMT_LOCAL bool psconvert_gs_is_good (int major, int minor) { EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { unsigned int i, j, k, pix_w = 0, pix_h = 0, got_BBatend; int sys_retval = 0, r, pos_file, pos_ext, error = 0, trans_line; + int n_read_PS_lines, max_PS_lines; size_t len, line_size = 0U, half_baked_size = 0; uint64_t pos = 0; bool got_BB, got_HRBB, file_has_HRBB, got_end, landscape, landscape_orig, set_background = false, old_transparency_code_needed; bool excessK, setup, found_proj = false, isGMT_PS = false, return_image = false, delete = false, file_processing = true; bool transparency = false, look_for_transparency, BeginPageSetup_here = false, has_transparency, add_grestore = false; + bool first_pagedevice = true; double xt, yt, xt_bak, yt_bak, w, h, x0 = 0.0, x1 = 612.0, y0 = 0.0, y1 = 828.0; double west = 0.0, east = 0.0, south = 0.0, north = 0.0; @@ -1661,7 +1664,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { ""}; /* bmpgray */ char *ext[N_GS_DEVICES] = {".eps", ".pdf", ".svg", ".jpg", ".png", ".ppm", ".tif", ".bmp", ".png", ".jpg", ".png", ".tif", ".bmp"}; char *RefLevel[N_KML_ELEVATIONS] = {"clampToGround", "relativeToGround", "absolute", "relativeToSeaFloor", "clampToSeaFloor"}; -#ifdef WIN32 +#ifdef _WIN32 char at_sign[2] = "@"; #else char at_sign[2] = ""; @@ -1703,6 +1706,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if ((error = parse (GMT, Ctrl, options)) != 0) Return (error); /*---------------------------- This is the psconvert main code ----------------------------*/ + + gmt_M_tic(GMT); if (!Ctrl->L.active && (GMT->current.setting.run_mode == GMT_CLASSIC) && (Ctrl->In.n_files == 0)) { /* No files given, bail */ GMT_Report (API, GMT_MSG_ERROR, "No PostScript files specified - exiting.\n"); @@ -1728,6 +1733,19 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { old_transparency_code_needed = (gsVersion.major == 9 && gsVersion.minor < 53); + if (old_transparency_code_needed && Ctrl->O.active) { + Ctrl->O.active = false; + GMT_Report (API, GMT_MSG_WARNING, "gs version %s does not support the -! option - please upgrade to 9.53 or later\n", GSstring); + } + if (Ctrl->T.eps == -1 && Ctrl->O.active) { /* -TE option. */ + Ctrl->O.active = false; + GMT_Report (API, GMT_MSG_WARNING, "The -TE option does not support the -!\n"); + } + if (Ctrl->N.BB_paint || Ctrl->N.outline) { + Ctrl->O.active = false; + GMT_Report (API, GMT_MSG_WARNING, "The -Ng or -Np option do not support the -!\n"); + } + if (Ctrl->T.device == GS_DEV_SVG && (gsVersion.major > 9 || (gsVersion.major == 9 && gsVersion.minor >= 16))) { GMT_Report (API, GMT_MSG_ERROR, "Your Ghostscript version (%s) no longer supports the SVG device.\n", GSstring); GMT_Report (API, GMT_MSG_ERROR, "We recommend converting to PDF and then installing the pdf2svg package.\n"); @@ -1815,6 +1833,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { ps_names[j++] = gmt_strdup_noquote (opt->arg); } } + if (GMT->current.setting.run_mode == GMT_MODERN) { /* Need to complete the half-baked PS file */ if (Ctrl->In.n_files == 0) { /* Add the default hidden PS file */ if ((k = gmt_set_psfilename (GMT)) == 0) { /* Get hidden file name for current PS */ @@ -1932,7 +1951,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { Return (GMT_RUNTIME_ERROR); } } - if (file_processing && (fp = fopen (ps_file, "r")) == NULL) { + if (file_processing && (fp = fopen (ps_file, "r+")) == NULL) { GMT_Report (API, GMT_MSG_ERROR, "Cannot open file %s\n", ps_file); continue; } @@ -1966,7 +1985,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if (fpo) {fclose (fpo); fpo = NULL;} Return (GMT_RUNTIME_ERROR); } - while (psconvert_file_line_reader (GMT, &line, &line_size, fp, PS->data, &pos) != EOF) { + while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF) { if (dump && !strncmp (line, "% Begin GMT time-stamp", 22)) dump = false; if (dump) @@ -2043,7 +2062,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { Return (GMT_RUNTIME_ERROR); Return (GMT_ERROR_ON_FOPEN); } - while ((psconvert_file_line_reader (GMT, &line, &line_size, fpb, NULL, NULL) != EOF) && !got_BB) { + while ((psconvert_file_line_reader (GMT, &line, &line_size, fpb) != EOF) && !got_BB) { /* We only use the High resolution BB */ if ((strstr (line,"%%HiResBoundingBox:"))) { sscanf (&line[19], "%s %s %s %s", c1, c2, c3, c4); @@ -2115,7 +2134,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { strcat (tmp_file, Ctrl->F.file); if (strlen(tmp_file) < PATH_MAX-4) /* To please Coverity */ strcat (tmp_file, ext[GS_DEV_EPS]); - if ((fpo = fopen (tmp_file, "w")) == NULL) { + if (!Ctrl->O.active && (fpo = fopen (tmp_file, "w")) == NULL) { GMT_Report (API, GMT_MSG_ERROR, "Unable to open file %s for writing\n", tmp_file); continue; } @@ -2125,7 +2144,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { sprintf (tmp_file, "%s/psconvert_%dd.eps", API->gwf_dir, (int)getpid()); else sprintf (tmp_file, "%s/psconvert_%dd.eps", Ctrl->D.dir, (int)getpid()); - if ((fpo = fopen (tmp_file, "w+")) == NULL) { + if (!Ctrl->O.active && (fpo = fopen (tmp_file, "w+")) == NULL) { GMT_Report (API, GMT_MSG_ERROR, "Unable to create a temporary file\n"); continue; } @@ -2135,7 +2154,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { * Since we prefer the HiResBB over BB we must continue to read until both are found or 20 lines have past */ i = 0; - while ((psconvert_file_line_reader (GMT, &line, &line_size, fp, PS->data, &pos) != EOF) && i < 20 && !(got_BB && got_HRBB && got_end)) { + while ((psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF) && i < 20 && !(got_BB && got_HRBB && got_end)) { i++; if (!line[0] || line[0] != '%') { /* Skip empty and non-comment lines */ } @@ -2190,7 +2209,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { GMT_Report (API, GMT_MSG_ERROR, "The file %s has no BoundingBox in the first 20 lines or last 256 bytes. Use -A option.\n", ps_file); if (!Ctrl->T.eps && gmt_remove_file (GMT, tmp_file)) { /* Remove the temporary EPS file */ - fclose (fp); fclose (fp2); fclose (fpo); + fclose (fp); fclose (fp2); + if (fpo) {fclose (fpo); fpo = NULL;} Return (GMT_RUNTIME_ERROR); } continue; @@ -2212,7 +2232,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { /* Rewind the input file and start copying and replacing */ /* ****************************************************************** */ - psconvert_file_rewind (fp, &pos); + rewind(fp); /* To produce non-PDF output from PS with transparency we must determine if transparency is requested in the PS */ look_for_transparency = Ctrl->T.device != GS_DEV_PDF && Ctrl->T.device != -GS_DEV_PDF; @@ -2220,15 +2240,53 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { set_background = (Ctrl->N.BB_paint || Ctrl->N.outline); trans_line = 0; - while (psconvert_file_line_reader (GMT, &line, &line_size, fp, PS->data, &pos) != EOF) { + if (Ctrl->O.active) { /* Use a fake fpo so that we don't have to modify the whole code. */ + if (fpo != NULL) fclose(fpo); +#ifdef _WIN32 + fpo = fopen("nul", "w"); +#else + fpo = fopen("dev/null", "w"); +#endif + } + + n_read_PS_lines = 0; + /* Max number of lines to read from file. Avoid reading entire file when Ctrl->O.active. 750 should be good. */ + max_PS_lines = (Ctrl->O.active) ? 750 : 100000000; + + while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF && n_read_PS_lines < max_PS_lines) { + n_read_PS_lines++; if (line[0] != '%') { /* Copy any non-comment line, except one containing setpagedevice in the Setup block */ if (!has_transparency) has_transparency = (strstr (line, " PSL_transp") != NULL); if (look_for_transparency && has_transparency) { transparency = true; /* Yes, found transparency */ look_for_transparency = false; /* No need to check anymore */ } - if (setup && strstr(line,"setpagedevice") != NULL) /* This is a "setpagedevice" command that should be avoided */ + + if (setup && strstr(line,"setpagedevice") != NULL) { /* This is a "setpagedevice" command that should be avoided */ + if (Ctrl->O.active) { + size_t len = strlen(line); + fseek(fp, (off_t)-(len +1), SEEK_CUR); /* Seek back to start of line (+1 why?) */ + if (first_pagedevice) { /* Some files have 1, others have 2 occurences of 'setpagedevice' */ + if (r != 0) { /* Rotations must come before translations */ + char t[GMT_LEN64] = ""; /* To hold the translation string */ + sprintf(line, "%d rotate\n", r); /* Now 'line' has new length */ + sprintf(t, "%g %g translate", xt, yt); + strcat(line, t); + for (int i = strlen(line)+strlen(t); i < len; i++) line[i] = ' '; /* Fill remainings with spaces */ + } + else + sprintf(line, "%g %g translate", xt, yt); + + first_pagedevice = false; + } + else + for (int i = 0; i < len; i++) line[i] = ' '; + + fprintf(fp, line); fflush(fp); + } continue; + } + if (old_transparency_code_needed && strstr (line, ".setfillconstantalpha")) { /* Our gs is too old so we must switch the modern transparency command to the older .setopacityalpha command. * At some point in the future we will abandon support for 9.52 and older and remove this entire if-test */ @@ -2247,9 +2305,11 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { } else fprintf (fpo, "%s\n", line); + continue; } - else if (!found_proj && !strncmp (&line[2], "PROJ", 4)) { /* Search for the PROJ tag in the ps file */ + else if (Ctrl->T.device == GS_DEV_PDF && !found_proj && !strncmp (&line[2], "PROJ", 4)) { + /* Search for the PROJ tag in the ps file. Restrict the search for the PDF case as it's only used there. */ char *ptmp = NULL, xx1[128], xx2[128], yy1[128], yy2[128]; sscanf (&line[8], "%s %s %s %s %s %s %s %s %s",proj4_name,xx1,xx2,yy1,yy2,c1,c2,c3,c4); west = atof (c1); east = atof (c2); @@ -2301,16 +2361,35 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if (Ctrl->I.resize) { /* Here the BB is the new size itself */ w_t = Ctrl->I.new_size[0]; h_t = Ctrl->I.new_size[1]; } - if (got_BB && !Ctrl->A.round) - fprintf (fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint (psconvert_smart_ceil(w_t)), lrint (psconvert_smart_ceil(h_t))); - else if (got_BB && Ctrl->A.round) /* Go against Adobe Law and round HRBB instead of ceil */ - fprintf (fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint (w_t), lrint (h_t)); + + if (Ctrl->O.active) { + fseek(fp, (off_t)-strlen(line), SEEK_CUR); /* Seek back to start of line */ + if (got_BB && !Ctrl->A.round) + sprintf(line, "%%%%BoundingBox: 0 0 %ld %ld", lrint (psconvert_smart_ceil(w_t)), lrint (psconvert_smart_ceil(h_t))); + else if (got_BB && Ctrl->A.round) /* Go against Adobe Law and round HRBB instead of ceil */ + sprintf(line, "%%%%BoundingBox: 0 0 %ld %ld", lrint(w_t), lrint(h_t)); + fprintf(fp, line); + fflush(fp); + } + else { + if (got_BB && !Ctrl->A.round) + fprintf (fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint (psconvert_smart_ceil(w_t)), lrint (psconvert_smart_ceil(h_t))); + else if (got_BB && Ctrl->A.round) /* Go against Adobe Law and round HRBB instead of ceil */ + fprintf (fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint (w_t), lrint (h_t)); + } got_BB = false; if (file_has_HRBB) continue; /* High-res BB will be put elsewhere */ - if (got_HRBB) - fprintf (fpo, "%%%%HiResBoundingBox: 0 0 %.4f %.4f\n", w_t, h_t); + if (got_HRBB) { /* TO DELETE?. This is silly, if we 'continue' above we can never come here. */ + if (Ctrl->O.active) { + fseek(fp, (off_t)-strlen(line), SEEK_CUR); /* Seek back to start of line */ + fprintf(fp, "%%%%HiResBoundingBox: 0 0 %.4f %.4f", w_t, h_t); + fflush(fp); + } + else + fprintf(fpo, "%%%%HiResBoundingBox: 0 0 %.4f %.4f\n", w_t, h_t); + } got_HRBB = false; continue; } @@ -2320,8 +2399,15 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if (Ctrl->I.resize) { /* Here the BB is the new size itself */ w_t = Ctrl->I.new_size[0]; h_t = Ctrl->I.new_size[1]; } - if (got_HRBB) - fprintf (fpo, "%%%%HiResBoundingBox: 0 0 %.4f %.4f\n", w_t, h_t); + if (got_HRBB) { + if (Ctrl->O.active) { + fseek(fp, (off_t)-(strlen(line)+0), SEEK_CUR); /* Seek back to start of line */ + fprintf(fp, "%%%%HiResBoundingBox: 0 0 %.4f %.4f", w_t, h_t); + fflush(fp); + } + else + fprintf(fpo, "%%%%HiResBoundingBox: 0 0 %.4f %.4f\n", w_t, h_t); + } got_HRBB = false; continue; } @@ -2334,7 +2420,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { setup = true; else if (!strncmp (line, "%%EndSetup", 10)) { setup = false; - if (Ctrl->T.eps == -1) /* Write out setpagedevice command */ + if (Ctrl->T.eps == -1) /* -TE option. Write out setpagedevice command. Note: The -! option cannot be active here. */ fprintf (fpo, "<< /PageSize [%g %g] >> setpagedevice\n", w, h); if (r != 0) fprintf (fpo, "%d rotate\n", r); @@ -2356,10 +2442,10 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { size_t Lsize = 128U; char *line_ = gmt_M_memory (GMT, NULL, Lsize, char); BeginPageSetup_here = true; /* Signal that on next line the job must be done */ - psconvert_file_line_reader (GMT, &line_, &Lsize, fp, PS->data, &pos); /* Read also next line which is to be overwritten (unless a comment) */ + psconvert_file_line_reader (GMT, &line_, &Lsize, fp); /* Read also next line which is to be overwritten (unless a comment) */ while (line_[0] == '%') { /* Skip all comments until we get the first actionable line */ strncpy(t3, line_, 127); - psconvert_file_line_reader (GMT, &line_, &Lsize, fp, PS->data, &pos); + psconvert_file_line_reader (GMT, &line_, &Lsize, fp); } /* The trouble is that we can have things like "V 612 0 T 90 R 0.06 0.06 scale" or "V 0.06 0.06 scale" */ @@ -2431,7 +2517,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { psconvert_possibly_fill_or_outline_BB (GMT, &(Ctrl->N), fpo); } } - else if (!strncmp (line, "%%Page:", 7)) { + else if (!strncmp (line, "%%Page:", 7)) { /* What is this for? */ if (r != 0) fprintf (fpo, "%d rotate\n", r); if (!gmt_M_is_zero (xt) || !gmt_M_is_zero (yt)) @@ -2446,8 +2532,11 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { fprintf (fpo, "V clippath %s %g %g /Normal PSL_transp F N U\n", ptr, Ctrl->N.fade_level, Ctrl->N.fade_level); transparency = true; } - else if (Ctrl->A.crop && found_proj && !strncmp (line, "%%PageTrailer", 13)) { - psconvert_file_line_reader (GMT, &line, &line_size, fp, PS->data, &pos); + else if (Ctrl->T.device == GS_DEV_PDF && Ctrl->A.crop && found_proj && !strncmp(line, "%%PageTrailer", 13)) { + /* This section is only needed when the output is PDF and adds GeoPDF tags. + It is ignored when -! is active because then fpo == NUL + */ + psconvert_file_line_reader (GMT, &line, &line_size, fp); fprintf (fpo, "%%%%PageTrailer\n"); fprintf (fpo, "%s\n", line); @@ -2504,17 +2593,18 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { } continue; } + fprintf (fpo, "%s\n", line); - } + } /* End while loop */ + if (add_grestore) fprintf (fpo, "grestore\n"); /* Since we started with gsave to change size */ /* Recede a bit to test the contents of last line. -7 for when PS has CRLF endings */ if (fseek (fp, (off_t)-7, SEEK_END)) GMT_Report (API, GMT_MSG_ERROR, "Seeking to spot 7 bytes earlier failed\n"); /* Read until last line is encountered */ - while (psconvert_file_line_reader (GMT, &line, &line_size, fp, PS->data, &pos) != EOF); - if (strncmp (line, "%%EOF", 5U)) - /* Possibly a non-closed GMT PS file. To be confirmed later */ + while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF); + if (strncmp (line, "%%EOF", 5U)) /* Possibly a non-closed GMT PS file. To be confirmed later */ excessK = true; fclose (fpo); fpo = NULL; @@ -2522,7 +2612,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if (has_transparency && gsVersion.major == 9 && (gsVersion.minor == 51 || gsVersion.minor == 52)) - GMT_Report (API, GMT_MSG_WARNING, "Input file has transparency but your gs version %s has a bug preventing it - please upgrade to 9.53\n", GSstring); + GMT_Report (API, GMT_MSG_WARNING, "Input file has transparency but your gs version %s has a bug preventing it - please upgrade to 9.53 or later\n", GSstring); if (transparency && Ctrl->T.device != GS_DEV_PDF) /* Must reset to PDF settings since we have transparency */ gs_params = (psconvert_gs_is_good (gsVersion.major, gsVersion.minor)) ? gs_params_pdfnew : gs_params_pdfold; @@ -2578,9 +2668,10 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { sprintf (resolution, "-g%dx%d -r%g -dDownScaleFactor=%d", pix_w * Ctrl->H.factor, pix_h * Ctrl->H.factor, Ctrl->E.dpi * Ctrl->H.factor, Ctrl->H.factor); else sprintf (resolution, "-g%dx%d -r%g", pix_w, pix_h, Ctrl->E.dpi); + sprintf (cmd, "%s%s %s %s%s -sDEVICE=%s %s %s -sOutputFile=%c%s%c %c%s%c", at_sign, Ctrl->G.file, gs_params, Ctrl->C.arg, psconvert_alpha_bits(Ctrl), device[Ctrl->T.device], - device_options[Ctrl->T.device], resolution, quote, out_file, quote, quote, tmp_file, quote); + device_options[Ctrl->T.device], resolution, quote, out_file, quote, quote, Ctrl->O.active ? ps_file : tmp_file, quote); if (Ctrl->S.active) { /* Print Ghostscript command */ API->print_func (GMT->session.std[GMT_ERR], cmd); @@ -2589,6 +2680,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { /* Execute the Ghostscript command */ GMT_Report (API, GMT_MSG_DEBUG, "Running: %s\n", cmd); + gmt_M_toc(GMT); + gmt_M_tic(GMT); /* Start timer to measure mostly the Ghostscript run time */ sys_retval = system (cmd); if (sys_retval) { GMT_Report (API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); @@ -2598,23 +2691,21 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { /* Check output file */ if (access (out_file, R_OK)) { /* output file not created */ - if (isGMT_PS && excessK) - /* non-closed GMT input PS file */ + if (isGMT_PS && excessK) /* non-closed GMT input PS file */ GMT_Report (API, GMT_MSG_ERROR, "%s: GMT PS format detected but file is not finalized. Maybe a -K in excess? No output created.\n", ps_file); - else - /* Either a bad closed GMT PS file or one of unknown origin */ + else /* Either a bad closed GMT PS file or one of unknown origin */ GMT_Report (API, GMT_MSG_ERROR, "Could not create %s. Maybe input file does not fulfill PS specifications.\n", out_file); } else { /* output file exists */ - if (isGMT_PS && excessK) - /* non-closed GMT input PS file */ + if (isGMT_PS && excessK) /* non-closed GMT input PS file */ GMT_Report (API, GMT_MSG_ERROR, "%s: GMT PS format detected but file is not finalized. Maybe a -K in excess? %s could be messed up.\n", ps_file, out_file); /* else: Either a good closed GMT PS file or one of unknown origin */ } + if (transparency) { /* Now convert temporary PDF to desired format */ char pdf_file[PATH_MAX] = {""}; GMT_Report (API, GMT_MSG_INFORMATION, "Convert PDF with transparency to %s...\n", tag); @@ -2626,6 +2717,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { strncat (out_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); else strcat (out_file, Ctrl->F.file); + strcat (out_file, ext[Ctrl->T.device]); /* After conversion, convert the tmp PDF file to desired format via a 2nd gs call */ sprintf (cmd, "%s%s %s %s%s -sDEVICE=%s %s %s -sOutputFile=%c%s%c %c%s%c", @@ -2650,13 +2742,20 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if (GMT->current.setting.run_mode == GMT_MODERN) { if (Ctrl->T.ps) { /* Under modern mode we can also save the PS file by renaming it */ - out_file[0] = '\0'; /* truncate string to build new output file */ + out_file[0] = '\0'; /* truncate string to build new output file */ if (Ctrl->D.active) sprintf (out_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ strcat (out_file, Ctrl->F.file); strcat (out_file, ".ps"); - GMT_Report (API, GMT_MSG_DEBUG, "Rename %s -> %s\n", tmp_file, out_file); - if (gmt_rename_file (GMT, tmp_file, out_file, GMT_COPY_FILE)) - Return (GMT_RUNTIME_ERROR); + if (Ctrl->O.active) { + GMT_Report (API, GMT_MSG_DEBUG, "Rename %s -> %s\n", ps_file, out_file); + if (gmt_rename_file (GMT, ps_file, out_file, GMT_RENAME_FILE)) + Return (GMT_RUNTIME_ERROR); + } + else { + GMT_Report (API, GMT_MSG_DEBUG, "Rename %s -> %s\n", tmp_file, out_file); + if (gmt_rename_file (GMT, tmp_file, out_file, GMT_COPY_FILE)) + Return (GMT_RUNTIME_ERROR); + } } } else if (Ctrl->Z.active && !delete) { /* Remove input file, if requested */ @@ -2692,7 +2791,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { } if (!Ctrl->S.active) { - if (!Ctrl->T.eps && gmt_remove_file (GMT, tmp_file)) + if (!Ctrl->T.eps && gmt_remove_file (GMT, tmp_file)) /* If -! the tmp_file does not exist but gmt_remove_file handles that */ Return (GMT_RUNTIME_ERROR); if (strlen (no_U_file) > 0 && gmt_remove_file (GMT, no_U_file)) /* empty string == file was not created */ Return (GMT_RUNTIME_ERROR); @@ -2722,12 +2821,12 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { y_inc = (north - south) / pix_h; } GMT_Report (API, GMT_MSG_INFORMATION, "width = %d\theight = %d\tX res = %f\tY res = %f\n", - pix_w, pix_h, x_inc, y_inc); + pix_w, pix_h, x_inc, y_inc); /* West and North of the world file contain the coordinates of the center of the pixel but our current values are of the NW corner of the pixel (pixel registration). So we'll move halph pixel inward. */ - west += x_inc / 2.0; north -= y_inc / 2.0; + west += x_inc / 2.0; north -= y_inc / 2.0; if (Ctrl->D.active) sprintf (world_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ if (Ctrl->F.active) { /* Must rip the raster file extension before adding the world one */ @@ -2895,7 +2994,7 @@ EXTERN_MSC int GMT_ps2raster (void *V_API, int mode, void *args) { return (GMT_NOT_A_VALID_MODULE); } -#ifdef WIN32 +#ifdef _WIN32 GMT_LOCAL int psconvert_ghostbuster(struct GMTAPI_CTRL *API, struct PSCONVERT_CTRL *C) { /* Search the Windows registry for the directory containing the gswinXXc.exe We do this by finding the GS_DLL that is a value of the HKLM\SOFTWARE\GPL Ghostscript\X.XX\ key @@ -3000,4 +3099,4 @@ GMT_LOCAL int psconvert_ghostbuster(struct GMTAPI_CTRL *API, struct PSCONVERT_CT return (GMT_NOERROR); } -#endif /* WIN32 */ +#endif /* _WIN32 */ From 06347539c5429ef5e7c6095afa362954c6d96870 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Wed, 27 Mar 2024 16:08:06 +0000 Subject: [PATCH 02/16] Apparently unix doesn't deal with gmt_M_toc(GMT); in the Return macro. --- src/psconvert.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/psconvert.c b/src/psconvert.c index 70b9765221b..aa5a6a63955 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -1116,7 +1116,7 @@ GMT_LOCAL int64_t psconvert_file_line_reader(struct GMT_CTRL *GMT, char **L, siz } #define bailout(code) {gmt_M_free_options(mode); return (code);} -#define Return(code) {gmt_M_toc(GMT); Free_Ctrl(GMT, Ctrl); gmt_end_module(GMT, GMT_cpy); bailout(code);} +#define Return(code) {Free_Ctrl(GMT, Ctrl); gmt_end_module(GMT, GMT_cpy); bailout(code);} GMT_LOCAL inline char *psconvert_alpha_bits (struct PSCONVERT_CTRL *Ctrl) { /* return alpha bits which are valid for the selected driver */ @@ -2980,6 +2980,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if (fpw != NULL) fclose (fpw); GMT_Report (API, GMT_MSG_DEBUG, "Final input buffer length was % "PRIuS "\n", line_size); + gmt_M_toc(GMT); + Return (GMT_NOERROR); } From b409cffb6741e1a535dd1a7678948f9ad6eeb6ee Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Wed, 27 Mar 2024 16:30:45 +0000 Subject: [PATCH 03/16] Try gmt_M_toc(GMT,"") again. --- src/psconvert.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index aa5a6a63955..5f5682b5a64 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -1116,7 +1116,7 @@ GMT_LOCAL int64_t psconvert_file_line_reader(struct GMT_CTRL *GMT, char **L, siz } #define bailout(code) {gmt_M_free_options(mode); return (code);} -#define Return(code) {Free_Ctrl(GMT, Ctrl); gmt_end_module(GMT, GMT_cpy); bailout(code);} +#define Return(code) {gmt_M_toc(GMT,""); Free_Ctrl(GMT, Ctrl); gmt_end_module(GMT, GMT_cpy); bailout(code);} GMT_LOCAL inline char *psconvert_alpha_bits (struct PSCONVERT_CTRL *Ctrl) { /* return alpha bits which are valid for the selected driver */ @@ -2680,8 +2680,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { /* Execute the Ghostscript command */ GMT_Report (API, GMT_MSG_DEBUG, "Running: %s\n", cmd); - gmt_M_toc(GMT); - gmt_M_tic(GMT); /* Start timer to measure mostly the Ghostscript run time */ + gmt_M_toc(GMT, ""); + gmt_M_tic(GMT, ""); /* Start timer to measure mostly the Ghostscript run time */ sys_retval = system (cmd); if (sys_retval) { GMT_Report (API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); @@ -2980,8 +2980,6 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { if (fpw != NULL) fclose (fpw); GMT_Report (API, GMT_MSG_DEBUG, "Final input buffer length was % "PRIuS "\n", line_size); - gmt_M_toc(GMT); - Return (GMT_NOERROR); } From f571a7160ec9d0738d7e30e2c1fca054ba29a9e9 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Wed, 27 Mar 2024 16:48:02 +0000 Subject: [PATCH 04/16] f --- src/psconvert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psconvert.c b/src/psconvert.c index 5f5682b5a64..c929a2f6ba1 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -2681,7 +2681,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { /* Execute the Ghostscript command */ GMT_Report (API, GMT_MSG_DEBUG, "Running: %s\n", cmd); gmt_M_toc(GMT, ""); - gmt_M_tic(GMT, ""); /* Start timer to measure mostly the Ghostscript run time */ + gmt_M_tic(GMT); /* Start timer to measure mostly the Ghostscript run time */ sys_retval = system (cmd); if (sys_retval) { GMT_Report (API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); From 76e01404c9a1f169a30c8783ef33757351853234 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Mon, 1 Apr 2024 02:01:24 +0100 Subject: [PATCH 05/16] Fix dumb error in typing the "/dev/null" file name. --- src/psconvert.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index c929a2f6ba1..e2216cfb6e9 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -2245,7 +2245,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { #ifdef _WIN32 fpo = fopen("nul", "w"); #else - fpo = fopen("dev/null", "w"); + fpo = fopen("/dev/null", "w"); #endif } @@ -2282,7 +2282,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { else for (int i = 0; i < len; i++) line[i] = ' '; - fprintf(fp, line); fflush(fp); + fprintf(fp, "%s", line); fflush(fp); } continue; } @@ -2363,12 +2363,12 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { } if (Ctrl->O.active) { - fseek(fp, (off_t)-strlen(line), SEEK_CUR); /* Seek back to start of line */ + fseek(fp, (off_t)-(strlen(line)+1), SEEK_CUR); /* Seek back to start of line */ if (got_BB && !Ctrl->A.round) sprintf(line, "%%%%BoundingBox: 0 0 %ld %ld", lrint (psconvert_smart_ceil(w_t)), lrint (psconvert_smart_ceil(h_t))); else if (got_BB && Ctrl->A.round) /* Go against Adobe Law and round HRBB instead of ceil */ sprintf(line, "%%%%BoundingBox: 0 0 %ld %ld", lrint(w_t), lrint(h_t)); - fprintf(fp, line); + fprintf(fp, "%s\n", line); fflush(fp); } else { @@ -2383,7 +2383,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { continue; /* High-res BB will be put elsewhere */ if (got_HRBB) { /* TO DELETE?. This is silly, if we 'continue' above we can never come here. */ if (Ctrl->O.active) { - fseek(fp, (off_t)-strlen(line), SEEK_CUR); /* Seek back to start of line */ + fseek(fp, (off_t)-(strlen(line)+1), SEEK_CUR); /* Seek back to start of line */ fprintf(fp, "%%%%HiResBoundingBox: 0 0 %.4f %.4f", w_t, h_t); fflush(fp); } @@ -2401,8 +2401,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { } if (got_HRBB) { if (Ctrl->O.active) { - fseek(fp, (off_t)-(strlen(line)+0), SEEK_CUR); /* Seek back to start of line */ - fprintf(fp, "%%%%HiResBoundingBox: 0 0 %.4f %.4f", w_t, h_t); + fseek(fp, (off_t)-(strlen(line)+1), SEEK_CUR); /* Seek back to start of line */ + fprintf(fp, "%%%%HiResBoundingBox: 0 0 %.4f %.4f", w_t, h_t); /* No '\n' here because orig line already has it */ fflush(fp); } else From 53beb8e980b46d229c9a03b5959d29dcb5bddc45 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Fri, 29 Nov 2024 18:05:14 +0000 Subject: [PATCH 06/16] Make the -! option active by default if GMT is build with /DPS_NO_DUP Build GMT with /DPS_NO_DUP or use add_definitions(/DPS_NO_DUP) in ConfigUser.cmake --- src/psconvert.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/psconvert.c b/src/psconvert.c index 30ed20b5d81..8adfc74fe7d 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -1733,6 +1733,10 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { old_transparency_code_needed = (gsVersion.major == 9 && gsVersion.minor < 53); +#ifdef PS_NO_DUP /* sets option -! by default. Build GMT with /DPS_NO_DUP or use add_definitions(/DPS_NO_DUP) in ConfigUser.cmake */ + Ctrl->O.active = true; +#endif + if (old_transparency_code_needed && Ctrl->O.active) { Ctrl->O.active = false; GMT_Report (API, GMT_MSG_WARNING, "gs version %s does not support the -! option - please upgrade to 9.53 or later\n", GSstring); From 86de8d493c20a9e8422bb24b09483f6b53b61ffe Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Sat, 30 Nov 2024 00:16:22 +0000 Subject: [PATCH 07/16] Some rework on how the no-dup is set. Now it is a compile time parameter. --- src/psconvert.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index 8adfc74fe7d..41ae202369b 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -816,7 +816,9 @@ static int usage (struct GMTAPI_CTRL *API, int level) { "Escape any +? modifier inside strings with \\."); if (API->GMT->current.setting.run_mode == GMT_CLASSIC) GMT_Usage (API, 1, "\n-Z Remove input PostScript file(s) after successful conversion."); +#ifndef PS_NO_DUP GMT_Usage (API, 1, "\n-! Modify the input PS file instead of creating a temp EPS. Some options like -Ng will disable it."); +#endif GMT_Option (API, "."); return (GMT_MODULE_USAGE); @@ -836,6 +838,11 @@ static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_ struct GMT_OPTION *opt = NULL; struct GMTAPI_CTRL *API = GMT->parent; +/* This a temporary setting till (if) we decide to make the insitu PS modification the default behavior. */ +#ifdef PS_NO_DUP /* Sets option -! by default. Build GMT with /DPS_NO_DUP or use add_definitions(/DPS_NO_DUP) in ConfigUser.cmake */ + Ctrl->O.active = true; +#endif + for (opt = options; opt; opt = opt->next) { switch (opt->option) { @@ -1013,7 +1020,13 @@ static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_ break; case '!': /* Modify input PS instead of creating a new temp EPS one */ +#ifdef PS_NO_DUP + /* In this case -! has the effect of disabling the insitu modification. That is, it reverts the global PS_NO_DUP */ + Ctrl->O.active = false; +#else + /* Here it is the contrary. -! has the effect of setting the insitu modification when that was not the default. */ Ctrl->O.active = true; +#endif break; default: /* Report bad options */ @@ -1630,7 +1643,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { bool got_BB, got_HRBB, file_has_HRBB, got_end, landscape, landscape_orig, set_background = false, old_transparency_code_needed; bool excessK, setup, found_proj = false, isGMT_PS = false, return_image = false, delete = false, file_processing = true; bool transparency = false, look_for_transparency, BeginPageSetup_here = false, has_transparency, add_grestore = false; - bool first_pagedevice = true; + bool first_pagedevice = true, found_EndProlog = false; double xt, yt, xt_bak, yt_bak, w, h, x0 = 0.0, x1 = 612.0, y0 = 0.0, y1 = 828.0; double west = 0.0, east = 0.0, south = 0.0, north = 0.0; @@ -1733,10 +1746,6 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { old_transparency_code_needed = (gsVersion.major == 9 && gsVersion.minor < 53); -#ifdef PS_NO_DUP /* sets option -! by default. Build GMT with /DPS_NO_DUP or use add_definitions(/DPS_NO_DUP) in ConfigUser.cmake */ - Ctrl->O.active = true; -#endif - if (old_transparency_code_needed && Ctrl->O.active) { Ctrl->O.active = false; GMT_Report (API, GMT_MSG_WARNING, "gs version %s does not support the -! option - please upgrade to 9.53 or later\n", GSstring); @@ -2255,11 +2264,15 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { } n_read_PS_lines = 0; - /* Max number of lines to read from file. Avoid reading entire file when Ctrl->O.active. 750 should be good. */ - max_PS_lines = (Ctrl->O.active) ? 750 : 100000000; + /* Max number of lines to read from file. Avoid reading entire file when Ctrl->O.active. 1000 should be good. */ + max_PS_lines = (Ctrl->O.active) ? 1000 : 100000000; while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF && n_read_PS_lines < max_PS_lines) { n_read_PS_lines++; + if (isGMT_PS && !found_EndProlog) { /* The %%EndProlog marks the end of a GMT PS header */ + found_EndProlog = strstr(line, "%%EndProlog"); /* Not starting the parsing before finding it saves as scanning ~700 lines */ + continue; + } if (line[0] != '%') { /* Copy any non-comment line, except one containing setpagedevice in the Setup block */ if (!has_transparency) has_transparency = (strstr (line, " PSL_transp") != NULL); if (look_for_transparency && has_transparency) { From f572a56d1c324dce7a164fa1172d826f6f850ef2 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Sun, 1 Dec 2024 19:15:24 +0000 Subject: [PATCH 08/16] Just force the build and CI again. --- src/psconvert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psconvert.c b/src/psconvert.c index 41ae202369b..6c1f3df3284 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -1021,7 +1021,7 @@ static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_ case '!': /* Modify input PS instead of creating a new temp EPS one */ #ifdef PS_NO_DUP - /* In this case -! has the effect of disabling the insitu modification. That is, it reverts the global PS_NO_DUP */ + /* In this case -! has the effect of disabling the insitu modification. That is, it reverts the global PS_NO_DUP. */ Ctrl->O.active = false; #else /* Here it is the contrary. -! has the effect of setting the insitu modification when that was not the default. */ From 0e5bb4bbfc306922ee6232a103b359b54b5b1ba7 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Wed, 4 Dec 2024 02:04:37 +0000 Subject: [PATCH 09/16] Fix logic on when not scan the first ~700 lines. --- src/psconvert.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index 6c1f3df3284..4f51b66ebae 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -2269,8 +2269,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF && n_read_PS_lines < max_PS_lines) { n_read_PS_lines++; - if (isGMT_PS && !found_EndProlog) { /* The %%EndProlog marks the end of a GMT PS header */ - found_EndProlog = strstr(line, "%%EndProlog"); /* Not starting the parsing before finding it saves as scanning ~700 lines */ + if (isGMT_PS && Ctrl->O.active && !found_EndProlog) { /* The %%EndProlog marks the end of a GMT PS header */ + found_EndProlog = (strstr(line, "%%EndProlog") != NULL); /* Not starting the parsing before finding it saves as scanning ~700 lines */ continue; } if (line[0] != '%') { /* Copy any non-comment line, except one containing setpagedevice in the Setup block */ From f50322cb42656219b2f79e67c527e66ef4ee52b2 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Fri, 13 Dec 2024 17:01:41 +0000 Subject: [PATCH 10/16] One more fix when looking for transparency and GeoTIFF production. --- src/psconvert.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index 4f51b66ebae..9d79c44181b 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -2267,7 +2267,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { /* Max number of lines to read from file. Avoid reading entire file when Ctrl->O.active. 1000 should be good. */ max_PS_lines = (Ctrl->O.active) ? 1000 : 100000000; - while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF && n_read_PS_lines < max_PS_lines) { + while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF && (look_for_transparency || n_read_PS_lines < max_PS_lines)) { n_read_PS_lines++; if (isGMT_PS && Ctrl->O.active && !found_EndProlog) { /* The %%EndProlog marks the end of a GMT PS header */ found_EndProlog = (strstr(line, "%%EndProlog") != NULL); /* Not starting the parsing before finding it saves as scanning ~700 lines */ @@ -2326,7 +2326,8 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { continue; } - else if (Ctrl->T.device == GS_DEV_PDF && !found_proj && !strncmp (&line[2], "PROJ", 4)) { + //else if (Ctrl->T.device == GS_DEV_PDF && !found_proj && !strncmp (&line[2], "PROJ", 4)) { + else if (!found_proj && !strncmp (&line[2], "PROJ", 4)) { /* Search for the PROJ tag in the ps file. Restrict the search for the PDF case as it's only used there. */ char *ptmp = NULL, xx1[128], xx2[128], yy1[128], yy2[128]; sscanf (&line[8], "%s %s %s %s %s %s %s %s %s",proj4_name,xx1,xx2,yy1,yy2,c1,c2,c3,c4); From 4e5a2c4fddfb9b3b9cd38ade6bf1745e1e833f92 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Sun, 5 Jan 2025 14:47:15 +0000 Subject: [PATCH 11/16] Be more specific on the -N variations that disable -! --- src/psconvert.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index 532477a9af9..d4782a48ccf 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -817,7 +817,7 @@ static int usage (struct GMTAPI_CTRL *API, int level) { if (API->GMT->current.setting.run_mode == GMT_CLASSIC) GMT_Usage (API, 1, "\n-Z Remove input PostScript file(s) after successful conversion."); #ifndef PS_NO_DUP - GMT_Usage (API, 1, "\n-! Modify the input PS file instead of creating a temp EPS. Some options like -Ng will disable it."); + GMT_Usage (API, 1, "\n-! Modify the input PS file instead of creating a temp EPS. Some options like -N+g or -N+p will disable it."); #endif GMT_Option (API, "."); @@ -1756,7 +1756,7 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { } if (Ctrl->N.BB_paint || Ctrl->N.outline) { Ctrl->O.active = false; - GMT_Report (API, GMT_MSG_WARNING, "The -Ng or -Np option do not support the -!\n"); + GMT_Report (API, GMT_MSG_WARNING, "The -N+g or -N+p options do not support the -!\n"); } if (Ctrl->T.device == GS_DEV_SVG && (gsVersion.major > 9 || (gsVersion.major == 9 && gsVersion.minor >= 16))) { From c303fe9fb1630003e31899c1871270a2a3a916cb Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Mon, 2 Jun 2025 00:54:38 +0100 Subject: [PATCH 12/16] Fix the case where psimage had imported another PS file. In that case, do not try to touch any further BoundingBox found. --- src/psconvert.c | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index d4782a48ccf..6381b980ef9 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -2367,63 +2367,47 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { "Very likely this won't work as you wish inside GE.\n"); } } - else if (!strncmp (line, "%GMTBoundingBox:", 16)) { - sscanf (&line[16], "%s %s %s %s",c1,c2,c3,c4); - gmtBB_x0 = atof (c1); gmtBB_y0 = atof (c2); - gmtBB_width = atof (c3); gmtBB_height = atof (c4); + else if (!strncmp(line, "%GMTBoundingBox:", 16)) { + sscanf(&line[16], "%s %s %s %s",c1,c2,c3,c4); + gmtBB_x0 = atof(c1); gmtBB_y0 = atof(c2); + gmtBB_width = atof(c3); gmtBB_height = atof(c4); continue; } - if (!strncmp (line, "%%BoundingBox:", 14)) { + if (!strncmp(line, "%%BoundingBox:", 14)) { double w_t, h_t; w_t = w; h_t = h; if (Ctrl->I.resize) { /* Here the BB is the new size itself */ w_t = Ctrl->I.new_size[0]; h_t = Ctrl->I.new_size[1]; } - if (Ctrl->O.active) { - fseek(fp, (off_t)-(strlen(line)+1), SEEK_CUR); /* Seek back to start of line */ - if (got_BB && !Ctrl->A.round) - sprintf(line, "%%%%BoundingBox: 0 0 %ld %ld", lrint (psconvert_smart_ceil(w_t)), lrint (psconvert_smart_ceil(h_t))); - else if (got_BB && Ctrl->A.round) /* Go against Adobe Law and round HRBB instead of ceil */ - sprintf(line, "%%%%BoundingBox: 0 0 %ld %ld", lrint(w_t), lrint(h_t)); - fprintf(fp, "%s\n", line); - fflush(fp); - } + if (Ctrl->O.active) + continue; /* Because with -! we already parsed the code where we put the BB. This one must be from a psimage import. */ else { if (got_BB && !Ctrl->A.round) - fprintf (fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint (psconvert_smart_ceil(w_t)), lrint (psconvert_smart_ceil(h_t))); + fprintf(fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint(psconvert_smart_ceil(w_t)), lrint(psconvert_smart_ceil(h_t))); else if (got_BB && Ctrl->A.round) /* Go against Adobe Law and round HRBB instead of ceil */ - fprintf (fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint (w_t), lrint (h_t)); + fprintf(fpo, "%%%%BoundingBox: 0 0 %ld %ld\n", lrint(w_t), lrint(h_t)); } got_BB = false; if (file_has_HRBB) continue; /* High-res BB will be put elsewhere */ if (got_HRBB) { /* TO DELETE?. This is silly, if we 'continue' above we can never come here. */ - if (Ctrl->O.active) { - fseek(fp, (off_t)-(strlen(line)+1), SEEK_CUR); /* Seek back to start of line */ - fprintf(fp, "%%%%HiResBoundingBox: 0 0 %.4f %.4f", w_t, h_t); - fflush(fp); - } - else - fprintf(fpo, "%%%%HiResBoundingBox: 0 0 %.4f %.4f\n", w_t, h_t); + fprintf(fpo, "%%%%HiResBoundingBox: 0 0 %.4f %.4f\n", w_t, h_t); } got_HRBB = false; continue; } - else if (!strncmp (line, "%%HiResBoundingBox:", 19)) { + else if (!strncmp(line, "%%HiResBoundingBox:", 19)) { double w_t, h_t; w_t = w; h_t = h; if (Ctrl->I.resize) { /* Here the BB is the new size itself */ w_t = Ctrl->I.new_size[0]; h_t = Ctrl->I.new_size[1]; } if (got_HRBB) { - if (Ctrl->O.active) { - fseek(fp, (off_t)-(strlen(line)+1), SEEK_CUR); /* Seek back to start of line */ - fprintf(fp, "%%%%HiResBoundingBox: 0 0 %.4f %.4f", w_t, h_t); /* No '\n' here because orig line already has it */ - fflush(fp); - } + if (Ctrl->O.active) + continue; /* As explained above, this one must be from a psimage PS import. */ else fprintf(fpo, "%%%%HiResBoundingBox: 0 0 %.4f %.4f\n", w_t, h_t); } From 9088b49d73ef281bd1f2e9e2beb37fd703e3533d Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Mon, 2 Jun 2025 19:00:59 +0100 Subject: [PATCH 13/16] When -Tp (keep postscript) do not remove the 'setpagedevice' lines. This seems to one of the last bit to make all the tests pass even with /DPS_NO_DUP --- src/psconvert.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index 6381b980ef9..f9accffc274 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -1634,7 +1634,7 @@ GMT_LOCAL bool psconvert_gs_is_good (int major, int minor) { return false; /* Not implemented (?) */ } -EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { +EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { unsigned int i, j, k, pix_w = 0, pix_h = 0, got_BBatend; int sys_retval = 0, r, pos_file, pos_ext, error = 0, trans_line; int n_read_PS_lines, max_PS_lines; @@ -2274,13 +2274,13 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { continue; } if (line[0] != '%') { /* Copy any non-comment line, except one containing setpagedevice in the Setup block */ - if (!has_transparency) has_transparency = (strstr (line, " PSL_transp") != NULL); + if (!has_transparency) has_transparency = (strstr(line, " PSL_transp") != NULL); if (look_for_transparency && has_transparency) { transparency = true; /* Yes, found transparency */ look_for_transparency = false; /* No need to check anymore */ } - if (setup && strstr(line,"setpagedevice") != NULL) { /* This is a "setpagedevice" command that should be avoided */ + if (setup && Ctrl->T.ps != 1 && strstr(line,"setpagedevice") != NULL) { /* This is a "setpagedevice" command that should be avoided */ if (Ctrl->O.active) { size_t len = strlen(line); fseek(fp, (off_t)-(len +1), SEEK_CUR); /* Seek back to start of line (+1 why?) */ @@ -2305,24 +2305,24 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { continue; } - if (old_transparency_code_needed && strstr (line, ".setfillconstantalpha")) { + if (old_transparency_code_needed && strstr(line, ".setfillconstantalpha")) { /* Our gs is too old so we must switch the modern transparency command to the older .setopacityalpha command. * At some point in the future we will abandon support for 9.52 and older and remove this entire if-test */ if (trans_line == 0) { /* First time we warn and deal with line number one in PSL_transp function */ - GMT_Report (API, GMT_MSG_DEBUG, "Your gs is older than 9.53 so we must replace .setfillconstantalpha with .setopacityalpha.\n"); - fprintf (fpo, " /.setopacityalpha where\n"); /* Look for old .setopacityalpha instead */ + GMT_Report(API, GMT_MSG_DEBUG, "Your gs is older than 9.53 so we must replace .setfillconstantalpha with .setopacityalpha.\n"); + fprintf(fpo, " /.setopacityalpha where\n"); /* Look for old .setopacityalpha instead */ } else - fprintf (fpo, " { pop PSL_BM_arg .setblendmode PSL_F_arg .setopacityalpha }\n"); /* Ignore the setstrokeconstantalpha value */ + fprintf(fpo, " { pop PSL_BM_arg .setblendmode PSL_F_arg .setopacityalpha }\n"); /* Ignore the setstrokeconstantalpha value */ trans_line++; } - else if (!old_transparency_code_needed && strstr (line, ".setopacityalpha")) { + else if (!old_transparency_code_needed && strstr(line, ".setopacityalpha")) { /* Our PostScript file was made before 6.2 master was updated to deal with new gs settings */ - GMT_Report (API, GMT_MSG_DEBUG, "Your gs is newer than 9.52 so we must replace .setopacityalpha in old PS files with .setfillconstantalpha.\n"); - fprintf (fpo, "/.setfillconstantalpha where {pop .setblendmode dup .setstrokeconstantalpha .setfillconstantalpha }{\n"); /* Use the transparency for both fill and stroke */ + GMT_Report(API, GMT_MSG_DEBUG, "Your gs is newer than 9.52 so we must replace .setopacityalpha in old PS files with .setfillconstantalpha.\n"); + fprintf(fpo, "/.setfillconstantalpha where {pop .setblendmode dup .setstrokeconstantalpha .setfillconstantalpha }{\n"); /* Use the transparency for both fill and stroke */ } else - fprintf (fpo, "%s\n", line); + fprintf(fpo, "%s\n", line); continue; } @@ -2415,20 +2415,20 @@ EXTERN_MSC int GMT_psconvert (void *V_API, int mode, void *args) { continue; } else if (Ctrl->P.active && landscape && !strncmp (line, "%%Orientation:", 14)) { - fprintf (fpo, "%%%%Orientation: Portrait\n"); + fprintf(fpo, "%%%%Orientation: Portrait\n"); landscape = false; continue; } - else if (!strncmp (line, "%%BeginSetup", 12)) + else if (!strncmp(line, "%%BeginSetup", 12)) setup = true; - else if (!strncmp (line, "%%EndSetup", 10)) { + else if (!strncmp(line, "%%EndSetup", 10)) { setup = false; if (Ctrl->T.eps == -1) /* -TE option. Write out setpagedevice command. Note: The -! option cannot be active here. */ - fprintf (fpo, "<< /PageSize [%g %g] >> setpagedevice\n", w, h); + fprintf(fpo, "<< /PageSize [%g %g] >> setpagedevice\n", w, h); if (r != 0) - fprintf (fpo, "%d rotate\n", r); + fprintf(fpo, "%d rotate\n", r); if (!gmt_M_is_zero (xt) || !gmt_M_is_zero (yt)) - fprintf (fpo, "%g %g translate\n", xt, yt); + fprintf(fpo, "%g %g translate\n", xt, yt); xt = yt = 0.0; r = 0; } From 2e00aef7d2906c9c0d97cbc0b82c9057a9e935ac Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Wed, 4 Jun 2025 04:04:11 +0100 Subject: [PATCH 14/16] Let it now also be able to process PS files and remain as PS --- src/postscriptlight.c | 6 ++- src/psconvert.c | 99 ++++++++++++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/postscriptlight.c b/src/postscriptlight.c index 80e7a18836f..8c5eb8c5b20 100644 --- a/src/postscriptlight.c +++ b/src/postscriptlight.c @@ -4742,9 +4742,11 @@ int PSL_beginplot (struct PSL_CTRL *PSL, FILE *fp, int orientation, int overlay, PSL_command (PSL, "PSLevel 1 gt { << /WhiteIsOpaque true >> setpagedevice } if\n"); if (manual_feed) /* Manual media feed requested */ PSL_command (PSL, "PSLevel 1 gt { << /ManualFeed true >> setpagedevice } if\n"); - else if (PSL->internal.p_width > 0.0 && PSL->internal.p_height > 0.0) /* Specific media selected */ - PSL_command (PSL, "PSLevel 1 gt { << /PageSize [%.12g %.12g] /ImagingBBox null >> setpagedevice } if \n", + else if (PSL->internal.p_width > 0.0 && PSL->internal.p_height > 0.0) { /* Specific media selected */ + PSL_command (PSL, "PSLevel 1 gt { << /PageSize [%.12g %.12g] /ImagingBBox null >> setpagedevice } if \n", PSL->internal.p_width, PSL->internal.p_height); /* Leave some space for eventual PageSize change by psconvert */ + PSL_command (PSL, "%% \n"); /* Space for eventual rot/translation by psconvert*/ + } if (PSL->init.copies > 1) PSL_command (PSL, "/#copies %d def\n", PSL->init.copies); PSL_command (PSL, "%%%%EndSetup\n\n"); diff --git a/src/psconvert.c b/src/psconvert.c index f9accffc274..72735663287 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -1096,6 +1096,9 @@ static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_ n_errors += gmt_M_check_condition (GMT, !Ctrl->F.active && GMT->current.setting.run_mode == GMT_MODERN, "Modern GMT mode requires the -F option\n"); + n_errors += gmt_M_check_condition (GMT, Ctrl->O.active && Ctrl->T.ps && !(GMT_PACKAGE_VERSION_MAJOR > 6 || GMT_PACKAGE_VERSION_MINOR >= 6), + "Insitu modification of PostScript files requires GMT 6.6 or later\n"); + return (n_errors ? GMT_PARSE_ERROR : GMT_NOERROR); } @@ -1641,9 +1644,9 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { size_t len, line_size = 0U, half_baked_size = 0; uint64_t pos = 0; bool got_BB, got_HRBB, file_has_HRBB, got_end, landscape, landscape_orig, set_background = false, old_transparency_code_needed; - bool excessK, setup, found_proj = false, isGMT_PS = false, return_image = false, delete = false, file_processing = true; + bool excessK, in_BeginSetup, found_proj = false, isGMT_PS = false, return_image = false, delete = false, file_processing = true; bool transparency = false, look_for_transparency, BeginPageSetup_here = false, has_transparency, add_grestore = false; - bool first_pagedevice = true, found_EndProlog = false; + bool first_pagedevice = true, found_EndProlog = false, second_ps = false; double xt, yt, xt_bak, yt_bak, w, h, x0 = 0.0, x1 = 612.0, y0 = 0.0, y1 = 828.0; double west = 0.0, east = 0.0, south = 0.0, north = 0.0; @@ -2014,7 +2017,7 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { file_processing = true; /* Since we now are reading a temporary file */ } - got_BB = got_HRBB = file_has_HRBB = got_end = landscape = landscape_orig = setup = false; + got_BB = got_HRBB = file_has_HRBB = got_end = landscape = landscape_orig = in_BeginSetup = false; got_BBatend = 0; len = strlen (ps_file); @@ -2219,12 +2222,12 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { /* Cannot proceed without knowing the BoundingBox */ if (!got_BB) { - GMT_Report (API, GMT_MSG_ERROR, - "The file %s has no BoundingBox in the first 20 lines or last 256 bytes. Use -A option.\n", ps_file); + GMT_Report(API, GMT_MSG_ERROR, + "The file %s has no BoundingBox in the first 20 lines or last 256 bytes. Use -A option.\n", ps_file); if (!Ctrl->T.eps && gmt_remove_file (GMT, tmp_file)) { /* Remove the temporary EPS file */ - if (fp != NULL) fclose (fp); - if (fp2 != NULL) fclose (fp2); - if (fpo != NULL) fclose (fpo); + if (fp != NULL) fclose(fp); + if (fp2 != NULL) fclose(fp2); + if (fpo != NULL) fclose(fpo); Return (GMT_RUNTIME_ERROR); } continue; @@ -2280,29 +2283,58 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { look_for_transparency = false; /* No need to check anymore */ } - if (setup && Ctrl->T.ps != 1 && strstr(line,"setpagedevice") != NULL) { /* This is a "setpagedevice" command that should be avoided */ - if (Ctrl->O.active) { - size_t len = strlen(line); - fseek(fp, (off_t)-(len +1), SEEK_CUR); /* Seek back to start of line (+1 why?) */ - if (first_pagedevice) { /* Some files have 1, others have 2 occurences of 'setpagedevice' */ - if (r != 0) { /* Rotations must come before translations */ - char t[GMT_LEN64] = ""; /* To hold the translation string */ - sprintf(line, "%d rotate\n", r); /* Now 'line' has new length */ - sprintf(t, "%g %g translate", xt, yt); - strcat(line, t); - for (int i = strlen(line)+strlen(t); i < len; i++) line[i] = ' '; /* Fill remainings with spaces */ + if (in_BeginSetup && strstr(line,"setpagedevice") != NULL) { /* This is a "setpagedevice" command that should be avoided */ + if (Ctrl->T.ps != 1) { /* Not PS */ + if (Ctrl->O.active) { + size_t len = strlen(line); + fseek(fp, (off_t)-(len +1), SEEK_CUR); /* Seek back to start of line (+1 why?) */ + if (first_pagedevice) { /* Some files have 1, others have 2 occurences of 'setpagedevice' */ + if (r != 0) { /* Rotations must come before translations */ + char t[GMT_LEN64] = ""; /* To hold the translation string */ + sprintf(line, "%d rotate\n", r); /* Now 'line' has new length */ + sprintf(t, "%g %g translate", xt, yt); + strcat(line, t); + for (int i = strlen(line)+strlen(t); i < len; i++) line[i] = ' '; /* Fill remainings with spaces */ + } + else + sprintf(line, "%g %g translate", xt, yt); + + first_pagedevice = false; } else - sprintf(line, "%g %g translate", xt, yt); + for (int i = 0; i < len; i++) line[i] = ' '; - first_pagedevice = false; + fprintf(fp, "%s", line); fflush(fp); } - else - for (int i = 0; i < len; i++) line[i] = ' '; + continue; + } + else { /* Resquested a PS output. Soo keep the setpagedevice but adjust the PageSize. */ + if (Ctrl->O.active) { + size_t len = strlen(line); + if (strstr(line,"PageSize") == NULL) continue; /* The other "setpagedevice" command. Too keep as is. */ + fseek(fp, (off_t)-(len +1), SEEK_CUR); /* Seek back to start of line */ + sprintf(line, "PSLevel 1 gt { << /PageSize [%.7g %.7g] /ImagingBBox null >> setpagedevice } if", x1-x0, y1-y0); + for (int i = strlen(line); i < len; i++) line[i] = ' '; /* Fill remainings with spaces */ + fprintf(fp, "%s", line); fflush(fp); + + psconvert_file_line_reader(GMT, &line, &line_size, fp); /* Read the next line */ + n_read_PS_lines++; + fseek(fp, (off_t)-(strlen(line) +1), SEEK_CUR); + if (r != 0) { /* Rotations must come before translations */ + char t[GMT_LEN32] = ""; /* To hold the translation string */ + sprintf(line, "%d R\n", r); /* Now 'line' has new length */ + sprintf(t, "%g %g T", xt, yt); + strcat(line, t); + } + else + sprintf(line, "%g %g T", xt, yt); - fprintf(fp, "%s", line); fflush(fp); + fprintf(fp, "%s", line); fflush(fp); + continue; + } + else if (strstr(line,"PageSize") != NULL) + sprintf(line, "PSLevel 1 gt { << /PageSize [%.7g %.7g] /ImagingBBox null >> setpagedevice } if", x1-x0, y1-y0); } - continue; } if (old_transparency_code_needed && strstr(line, ".setfillconstantalpha")) { @@ -2420,9 +2452,9 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { continue; } else if (!strncmp(line, "%%BeginSetup", 12)) - setup = true; + in_BeginSetup = true; else if (!strncmp(line, "%%EndSetup", 10)) { - setup = false; + in_BeginSetup = false; if (Ctrl->T.eps == -1) /* -TE option. Write out setpagedevice command. Note: The -! option cannot be active here. */ fprintf(fpo, "<< /PageSize [%g %g] >> setpagedevice\n", w, h); if (r != 0) @@ -2613,6 +2645,15 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { fclose (fpo); fpo = NULL; fclose (fp); fp = NULL; + if (!Ctrl->O.active && Ctrl->T.ps && GMT->current.setting.run_mode == GMT_CLASSIC) { + second_ps = true; /* Tell the renaming branch of modern mode to deal with this case too */ + if (!Ctrl->F.file) { + size_t len = strlen(ps_file); + Ctrl->F.file = strdup(ps_file); + Ctrl->F.file[len - 3] = '_'; /* Change the last ".ps" to "_2" */ + Ctrl->F.file[len - 2] = '2'; Ctrl->F.file[len - 1] = '\0'; + } + } if (has_transparency && gsVersion.major == 9 && (gsVersion.minor == 51 || gsVersion.minor == 52)) GMT_Report (API, GMT_MSG_WARNING, "Input file has transparency but your gs version %s has a bug preventing it - please upgrade to 9.53 or later\n", GSstring); @@ -2639,7 +2680,7 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { strcat (out_file, "_intermediate"); } else { /* Output is the final result */ - GMT_Report (API, GMT_MSG_INFORMATION, "Convert to %s...\n", tag); + GMT_Report (API, GMT_MSG_INFORMATION, "Convert to %s...\n", tag); if (Ctrl->D.active) sprintf (out_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ if (!Ctrl->F.active || return_image) @@ -2743,7 +2784,7 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { } } - if (GMT->current.setting.run_mode == GMT_MODERN) { + if (GMT->current.setting.run_mode == GMT_MODERN || second_ps) { /* Modern mode or -Tp where we also want to save the XXX.eps as a ps file */ if (Ctrl->T.ps) { /* Under modern mode we can also save the PS file by renaming it */ out_file[0] = '\0'; /* truncate string to build new output file */ if (Ctrl->D.active) sprintf (out_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ From 34431a1e4f3366b2ac0a634fceb54bbe9830ecd1 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Wed, 4 Jun 2025 20:44:03 +0100 Subject: [PATCH 15/16] Add the possibility of also cropping a pure PS file (Classic mode only). Tried to extend this to modern mode but it breaks all modern mode tests. --- src/gmt_init.c | 20 +++++++++++++++---- src/gmt_plot.c | 10 ++++++++-- src/psconvert.c | 52 ++++++++++++++++++++++++------------------------- 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/gmt_init.c b/src/gmt_init.c index c207166726d..9bb6adda27b 100644 --- a/src/gmt_init.c +++ b/src/gmt_init.c @@ -19564,7 +19564,7 @@ GMT_LOCAL int gmtinit_process_figures (struct GMTAPI_CTRL *API, char *show) { char pen[GMT_LEN32] = {""}, fill[GMT_LEN32] = {""}, off[GMT_LEN32] = {""}, device_extra[GMT_LEN8] = {""}, *do_gray[2] = {"", "+m"}; char *copy = NULL, *ptr = NULL, *format = NULL, *c = NULL; struct GMT_FIGURE *fig = NULL; - bool not_PS, auto_size; + bool not_PS = true, auto_size; int error, k, f, nf, n_figs, n_orig, gcode[GMT_LEN16], jpeg_quality = GMT_JPEG_DEF_QUALITY, monochrome = 0; unsigned int pos = 0; double legend_width = 0.0, legend_scale = 1.0; @@ -19578,6 +19578,7 @@ GMT_LOCAL int gmtinit_process_figures (struct GMTAPI_CTRL *API, char *show) { GMT_Report (API, GMT_MSG_ERROR, "Unable to open gmt.figures for reading\n"); return GMT_ERROR_ON_FOPEN; } + if ((n_figs = gmtinit_read_figures (API->GMT, 2, &fig)) == GMT_NOTSET) { /* Auto-insert the hidden gmt_0.ps- file which may not have been used */ GMT_Report (API, GMT_MSG_ERROR, "Unable to open gmt.figures for reading\n"); return GMT_ERROR_ON_FOPEN; @@ -19588,6 +19589,7 @@ GMT_LOCAL int gmtinit_process_figures (struct GMTAPI_CTRL *API, char *show) { for (k = 0; k < n_figs; k++) { if (!strcmp (fig[k].prefix, "-")) continue; /* Unnamed outputs are left for manual psconvert calls by external APIs */ GMT_Report (API, GMT_MSG_INFORMATION, "Processing GMT figure #%d [%s %s %s]\n", fig[k].ID, fig[k].prefix, fig[k].formats, fig[k].options); + /* Go through the format list and build array for -T arguments */ nf = gmtinit_get_graphics_formats (API->GMT, fig[k].formats, fmt, gcode, &jpeg_quality, &monochrome); if (n_orig && k) { /* Specified one or more figs via gmt figure so must switch to the current figure and update the history */ @@ -19598,22 +19600,27 @@ GMT_LOCAL int gmtinit_process_figures (struct GMTAPI_CTRL *API, char *show) { } gmtinit_get_history (API->GMT); /* Make sure we have the latest history for this figure */ } + copy = strdup (fig[k].formats); ptr = copy; for (f = 0; f < nf; f++) { /* Loop over all desired output formats */ format = strsep (&ptr, ","); /* Name of next format as user specified it */ device_extra[0] = '\0'; /* Reset device arguments */ if (fmt[f] == 'j' && jpeg_quality != GMT_JPEG_DEF_QUALITY) sprintf (device_extra, "+q%d", jpeg_quality); /* Need to pass quality modifier */ + mark = '-'; /* This is the last char in extension for a half-baked GMT PostScript file */ snprintf (cmd, GMT_BUFSIZ, "%s/gmt_%d.ps%c", API->gwf_dir, fig[k].ID, mark); /* Check if the file exists */ + if (access (cmd, F_OK)) { /* No such file, check if the fully baked file is there instead */ mark = '+'; /* This is the last char in extension for a fully-baked GMT PostScript file */ snprintf (cmd, GMT_BUFSIZ, "%s/gmt_%d.ps%c", API->gwf_dir, fig[k].ID, mark); /* Check if the file exists */ if (access (cmd, F_OK)) { /* No such file ether, give up; warn if a fig set via gmt figure (k > 0) and it is not the movie_background case which may not have a plot to go with it */ - if (k && strcmp (fig[k].prefix, "movie_background")) GMT_Report (API, GMT_MSG_WARNING, "Figure # %d (%s) was registered but no matching PostScript-|+ file found - skipping\n", fig[k].ID, fig[k].prefix); + if (k && strcmp (fig[k].prefix, "movie_background")) + GMT_Report (API, GMT_MSG_WARNING, "Figure # %d (%s) was registered but no matching PostScript-|+ file found - skipping\n", fig[k].ID, fig[k].prefix); continue; } } + if (gmt_get_legend_info (API, &legend_width, &legend_scale, legend_justification, pen, fill, off)) { /* Unplaced legend file */ /* Default to white legend with 1p frame offset 0.2 cm from selected justification point [TR] */ bool active = API->GMT->common.l.active; /* Must temporarily turn off -l since should not be passed to legend and plot */ @@ -19638,11 +19645,14 @@ GMT_LOCAL int gmtinit_process_figures (struct GMTAPI_CTRL *API, char *show) { } else /* Place products in current directory */ snprintf (cmd, GMT_BUFSIZ, "'%s/gmt_%d.ps-' -T%c%s%s -F%s", API->gwf_dir, fig[k].ID, fmt[f], device_extra, do_gray[monochrome], fig[k].prefix); + gmt_filename_get (fig[k].prefix); - not_PS = (fmt[f] != 'p'); /* Do not add convert options if plain PS */ /* Append psconvert optional settings */ + auto_size = gmtinit_check_if_autosize (API, fig[k].ID); /* Determine if the PostScript file has auto size (32767x32767) enabled */ + /* Next line is risky. See comments on line #9014 of gmt_plot.c/gmt_plotinit() */ + if (!auto_size) not_PS = (fmt[f] != 'p'); /* Do not add convert options if plain PS and a explicit paper size was set. */ + dir[0] = '\0'; /* No directory via D<dir> convert option */ - auto_size = gmtinit_check_if_autosize (API, fig[k].ID); /* Determine if the PostScript file has auto size enabled */ if (fig[k].options[0]) { /* Append figure-specific psconvert settings */ pos = 0; /* Reset position counter */ while ((gmt_strtok (fig[k].options, ",", &pos, p))) { @@ -19675,6 +19685,7 @@ GMT_LOCAL int gmtinit_process_figures (struct GMTAPI_CTRL *API, char *show) { } else if (not_PS && auto_size) /* No specific settings but must always add -A if not PostScript unless when media size is given */ strcat (cmd, " -A"); + GMT_Report (API, GMT_MSG_DEBUG, "psconvert: %s\n", cmd); if ((error = GMT_Call_Module (API, "psconvert", GMT_MODULE_CMD, cmd))) { GMT_Report (API, GMT_MSG_ERROR, "Failed to call psconvert\n"); @@ -19682,6 +19693,7 @@ GMT_LOCAL int gmtinit_process_figures (struct GMTAPI_CTRL *API, char *show) { gmt_M_str_free (copy); return error; } + if (!strncmp (format, "jpeg", 4U) || !strncmp (format, "tiff", 4U)) { /* Must rename file to have .jpeg or .tiff extensions */ /* Since psconvert cannot tell from j and t if the extensions should be 3 or 4 characters... */ char old_name[PATH_MAX] = {""}, new_name[PATH_MAX] = {""}, ext[GMT_LEN8] = {""}; diff --git a/src/gmt_plot.c b/src/gmt_plot.c index e2e5e4e2463..5f0dd3ff3bc 100644 --- a/src/gmt_plot.c +++ b/src/gmt_plot.c @@ -8989,7 +8989,7 @@ struct PSL_CTRL *gmt_plotinit (struct GMT_CTRL *GMT, struct GMT_OPTION *options) GMT_Report (GMT->parent, GMT_MSG_DEBUG, "Running in PS mode %s\n", ps_mode[GMT->current.setting.run_mode]); if (GMT->current.setting.run_mode == GMT_MODERN) { /* Write PS to hidden gmt_#.ps- file. No -O -K allowed */ char *verb[2] = {"Create", "Append to"}; - bool wants_PS; + bool wants_PS = false; double paper_margin = GMT_PAPER_MARGIN_AUTO; if (gmtlib_fixed_paper_size (GMT->parent)) { /* Must honor paper size and regular margin */ @@ -9008,9 +9008,15 @@ struct PSL_CTRL *gmt_plotinit (struct GMT_CTRL *GMT, struct GMT_OPTION *options) GMT->parent->error = GMT_ERROR_ON_FOPEN; return NULL; } - O_active = (k) ? true : false; /* -O is determined by presence or absence of hidden PS file */ + /* Determine paper size */ wants_PS = gmtlib_fig_is_ps (GMT); /* True if we have requested a PostScript output format */ + /* Next line would let modern mode use "auto" paper size (the 11 m wall-size) to correctly crop also a PS + file (currently it sets the A4 size as default), but that breaks all modern mode tests. It also terribly + slows down the tests when the -! option is built in to be the default (The /DPS_NO_DUP) */ + //if (!auto_media) wants_PS = gmtlib_fig_is_ps (GMT); /* True if we have requested a PostScript output AND set paper size. */ + + O_active = (k) ? true : false; /* -O is determined by presence or absence of hidden PS file */ if (wants_PS && !O_active) { /* Requesting a new PostScript file in modern mode */ if (auto_media) { /* Cannot use "auto" if requesting a PostScript file */ GMT_Report (GMT->parent, GMT_MSG_INFORMATION, "You should specify a paper size when requesting a PostScript file.\n"); diff --git a/src/psconvert.c b/src/psconvert.c index 72735663287..559b18bcbab 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -2174,44 +2174,40 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { i++; if (!line[0] || line[0] != '%') { /* Skip empty and non-comment lines */ } - else if (!got_BB && strstr (line, "%%BoundingBox:")) { - sscanf (&line[14], "%s %s %s %s",c1,c2,c3,c4); - if (strncmp (c1, "(atend)", 7)) { /* Got actual numbers */ + else if (!got_BB && strstr(line, "%%BoundingBox:")) { + sscanf(&line[14], "%s %s %s %s",c1,c2,c3,c4); + if (strncmp(c1, "(atend)", 7)) { /* Got actual numbers */ if (!got_HRBB) { /* Only assign values if we haven't seen the high-res version yet */ - x0 = atoi (c1); y0 = atoi (c2); - x1 = atoi (c3); y1 = atoi (c4); + x0 = atoi(c1); y0 = atoi(c2); + x1 = atoi(c3); y1 = atoi(c4); } got_BB = true; } else got_BBatend++; } - else if ((strstr (line, "%%HiResBoundingBox:"))) { + else if ((strstr(line, "%%HiResBoundingBox:"))) { file_has_HRBB = true; if (!got_HRBB) { - sscanf (&line[19], "%s %s %s %s",c1,c2,c3,c4); - if (strncmp (c1, "(atend)", 7)) { /* Got actual numbers */ - x0 = atof (c1); y0 = atof (c2); - x1 = atof (c3); y1 = atof (c4); + sscanf(&line[19], "%s %s %s %s",c1,c2,c3,c4); + if (strncmp(c1, "(atend)", 7)) { /* Got actual numbers */ + x0 = atof(c1); y0 = atof(c2); + x1 = atof(c3); y1 = atof(c4); got_HRBB = got_BB = true; } } } - else if ((strstr (line, "%%Creator:"))) { - if (!strncmp (&line[11], "GMT", 3)) - isGMT_PS = true; - } - else if ((strstr (line, "%%Orientation:"))) { - if (!strncmp (&line[15], "Landscape", 9)) - landscape = landscape_orig = true; - } - else if ((strstr (line, "%%EndComments"))) + else if ((strstr(line, "%%Creator:")) && !strncmp(&line[11], "GMT", 3)) + isGMT_PS = true; + else if ((strstr(line, "%%Orientation:")) &&!strncmp(&line[15], "Landscape", 9)) + landscape = landscape_orig = true; + else if ((strstr(line, "%%EndComments"))) got_end = true; if (got_BBatend == 1 && (got_end || i == 19)) { /* Now is the time to look at the end of the file */ got_BBatend++; /* Avoid jumping more than once to the end */ if (file_processing) { - if (fseek (fp, (off_t)-256, SEEK_END)) - GMT_Report (API, GMT_MSG_ERROR, "Seeking to start of last 256 bytes failed\n"); + if (fseek(fp, (off_t)-256, SEEK_END)) + GMT_Report(API, GMT_MSG_ERROR, "Seeking to start of last 256 bytes failed\n"); } else { /* Get towards end of string */ pos = (PS->n_bytes > 256) ? PS->n_bytes - 256 : 0; @@ -2308,7 +2304,7 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { } continue; } - else { /* Resquested a PS output. Soo keep the setpagedevice but adjust the PageSize. */ + else { /* Resquested a PS output. So keep the setpagedevice but adjust the PageSize. */ if (Ctrl->O.active) { size_t len = strlen(line); if (strstr(line,"PageSize") == NULL) continue; /* The other "setpagedevice" command. Too keep as is. */ @@ -2323,13 +2319,17 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { if (r != 0) { /* Rotations must come before translations */ char t[GMT_LEN32] = ""; /* To hold the translation string */ sprintf(line, "%d R\n", r); /* Now 'line' has new length */ - sprintf(t, "%g %g T", xt, yt); - strcat(line, t); + if (xt != 0.0 || yt != 0.0) { + sprintf(t, "%g %g T", xt, yt); + strcat(line, t); + } + fprintf(fp, "%s", line); fflush(fp); } - else + else if (xt != 0.0 || yt != 0.0) { sprintf(line, "%g %g T", xt, yt); + fprintf(fp, "%s", line); fflush(fp); + } - fprintf(fp, "%s", line); fflush(fp); continue; } else if (strstr(line,"PageSize") != NULL) From 4beadebc15d8d2278a6f4f8d7a0fbeb41685c302 Mon Sep 17 00:00:00 2001 From: Joaquim <jluis@ualg.pt> Date: Sun, 15 Jun 2025 18:04:00 +0100 Subject: [PATCH 16/16] Fix the situation where Landscape files worked well on first run but no subsequent. Problem was that dimension were modified to Portrait but Orientation in header remained unchanged saying it was Landscape. --- src/psconvert.c | 397 +++++++++++++++++++++++++----------------------- 1 file changed, 203 insertions(+), 194 deletions(-) diff --git a/src/psconvert.c b/src/psconvert.c index 559b18bcbab..a412a25bb3f 100644 --- a/src/psconvert.c +++ b/src/psconvert.c @@ -824,7 +824,7 @@ static int usage (struct GMTAPI_CTRL *API, int level) { return (GMT_MODULE_USAGE); } -static int parse (struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_OPTION *options) { +static int parse(struct GMT_CTRL *GMT, struct PSCONVERT_CTRL *Ctrl, struct GMT_OPTION *options) { /* This parses the options provided to psconvert and sets parameters in CTRL. * Any GMT common options will override values set previously by other commands. * It also replaces any file names specified as input or output with the data ID @@ -2054,114 +2054,113 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { GMT_Report (API, GMT_MSG_DEBUG, "Running: %s\n", cmd); sys_retval = system (cmd); /* Execute the command that computes the tight BB */ if (sys_retval) { - GMT_Report (API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); - fclose (fp); - if (fp2) fclose (fp2); + GMT_Report(API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); + fclose(fp); + if (fp2) fclose(fp2); fp = fp2 = NULL; - gmt_M_free (GMT, PS); - if (gmt_remove_file (GMT, BB_file)) - Return (GMT_RUNTIME_ERROR); - if (gmt_truncate_file (API, ps_file, half_baked_size)) - Return (GMT_RUNTIME_ERROR); - if (delete && gmt_remove_file (GMT, ps_file)) /* Since we created a temporary file from the memdata */ - Return (GMT_RUNTIME_ERROR); - Return (GMT_RUNTIME_ERROR); + gmt_M_free(GMT, PS); + if (gmt_remove_file(GMT, BB_file)) + Return(GMT_RUNTIME_ERROR); + if (gmt_truncate_file(API, ps_file, half_baked_size)) + Return(GMT_RUNTIME_ERROR); + if (delete && gmt_remove_file(GMT, ps_file)) /* Since we created a temporary file from the memdata */ + Return(GMT_RUNTIME_ERROR); + Return(GMT_RUNTIME_ERROR); } - if ((fpb = fopen (BB_file, "r")) == NULL) { - GMT_Report (API, GMT_MSG_ERROR, "Unable to open file %s\n", BB_file); - gmt_M_free (GMT, PS); - fclose (fp); fclose (fp2); + if ((fpb = fopen(BB_file, "r")) == NULL) { + GMT_Report(API, GMT_MSG_ERROR, "Unable to open file %s\n", BB_file); + gmt_M_free(GMT, PS); + fclose(fp); fclose(fp2); fp = fp2 = NULL; - if (gmt_truncate_file (API, ps_file, half_baked_size)) - Return (GMT_RUNTIME_ERROR); + if (gmt_truncate_file(API, ps_file, half_baked_size)) + Return(GMT_RUNTIME_ERROR); if (delete && gmt_remove_file (GMT, ps_file)) /* Since we created a temporary file from the memdata */ - Return (GMT_RUNTIME_ERROR); - Return (GMT_ERROR_ON_FOPEN); + Return(GMT_RUNTIME_ERROR); + Return(GMT_ERROR_ON_FOPEN); } - while ((psconvert_file_line_reader (GMT, &line, &line_size, fpb) != EOF) && !got_BB) { + while ((psconvert_file_line_reader(GMT, &line, &line_size, fpb) != EOF) && !got_BB) { /* We only use the High resolution BB */ - if ((strstr (line,"%%HiResBoundingBox:"))) { + if ((strstr(line,"%%HiResBoundingBox:"))) { sscanf (&line[19], "%s %s %s %s", c1, c2, c3, c4); x0 = atof (c1); y0 = atof (c2); x1 = atof (c3); y1 = atof (c4); x0 -= Ctrl->I.margin[XLO]; x1 += Ctrl->I.margin[XHI]; /* If not given, margin = 0/0/0/0 */ y0 -= Ctrl->I.margin[YLO]; y1 += Ctrl->I.margin[YHI]; if (x1 <= x0 || y1 <= y0) { - GMT_Report (API, GMT_MSG_ERROR, "Unable to decode BoundingBox file %s (maybe no non-white features were plotted?)\n", BB_file); - fclose (fpb); fpb = NULL; /* so we don't accidentally close twice */ + GMT_Report(API, GMT_MSG_ERROR, "Unable to decode BoundingBox file %s (maybe no non-white features were plotted?)\n", BB_file); + fclose(fpb); fpb = NULL; /* so we don't accidentally close twice */ if (Ctrl->D.active) sprintf (tmp_file, "%s/", Ctrl->D.dir); - strncat (tmp_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); - strcat (tmp_file, ext[Ctrl->T.device]); - sprintf (cmd, "%s%s %s %s%s -sDEVICE=%s %s -g1x1 -r%g -sOutputFile=%c%s%c %c%s%c", - at_sign, Ctrl->G.file, gs_params, Ctrl->C.arg, psconvert_alpha_bits(Ctrl), device[Ctrl->T.device], - device_options[Ctrl->T.device], - Ctrl->E.dpi, quote, tmp_file, quote, quote, ps_file, quote); - GMT_Report (API, GMT_MSG_DEBUG, "Running: %s\n", cmd); - sys_retval = system (cmd); /* Execute the Ghostscript command */ + strncat(tmp_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); + strcat(tmp_file, ext[Ctrl->T.device]); + sprintf(cmd, "%s%s %s %s%s -sDEVICE=%s %s -g1x1 -r%g -sOutputFile=%c%s%c %c%s%c", + at_sign, Ctrl->G.file, gs_params, Ctrl->C.arg, psconvert_alpha_bits(Ctrl), device[Ctrl->T.device], + device_options[Ctrl->T.device], Ctrl->E.dpi, quote, tmp_file, quote, quote, ps_file, quote); + GMT_Report(API, GMT_MSG_DEBUG, "Running: %s\n", cmd); + sys_retval = system(cmd); /* Execute the Ghostscript command */ if (Ctrl->S.active) { - API->print_func (GMT->session.std[GMT_ERR], cmd); - API->print_func (GMT->session.std[GMT_ERR], "\n"); + API->print_func(GMT->session.std[GMT_ERR], cmd); + API->print_func(GMT->session.std[GMT_ERR], "\n"); } if (sys_retval) { - GMT_Report (API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); - if (gmt_remove_file (GMT, tmp_file)) /* Remove the file */ - Return (GMT_RUNTIME_ERROR); - if (gmt_truncate_file (API, ps_file, half_baked_size)) - Return (GMT_RUNTIME_ERROR); - if (delete && gmt_remove_file (GMT, ps_file)) /* Since we created a temporary file from the memdata */ - Return (GMT_RUNTIME_ERROR); - gmt_M_free (GMT, PS); - fclose (fp); fclose (fp2); + GMT_Report(API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); + if (gmt_remove_file(GMT, tmp_file)) /* Remove the file */ + Return(GMT_RUNTIME_ERROR); + if (gmt_truncate_file(API, ps_file, half_baked_size)) + Return(GMT_RUNTIME_ERROR); + if (delete && gmt_remove_file(GMT, ps_file)) /* Since we created a temporary file from the memdata */ + Return(GMT_RUNTIME_ERROR); + gmt_M_free(GMT, PS); + fclose(fp); fclose(fp2); fp = fp2 = NULL; - Return (GMT_RUNTIME_ERROR); + Return(GMT_RUNTIME_ERROR); } /* must leave loop because fpb has been closed and psconvert_file_line_reader would * read from closed file: */ break; } got_BB = got_HRBB = true; - GMT_Report (API, GMT_MSG_INFORMATION, "Figure dimensions: Width: %g points [%g %s] Height: %g points [%g %s]\n", - x1-x0, (x1-x0)*GMT->session.u2u[GMT_PT][GMT->current.setting.proj_length_unit], - API->GMT->session.unit_name[API->GMT->current.setting.proj_length_unit], - y1-y0, (y1-y0)*GMT->session.u2u[GMT_PT][GMT->current.setting.proj_length_unit], - API->GMT->session.unit_name[API->GMT->current.setting.proj_length_unit]); + GMT_Report(API, GMT_MSG_INFORMATION, "Figure dimensions: Width: %g points [%g %s] Height: %g points [%g %s]\n", + x1-x0, (x1-x0)*GMT->session.u2u[GMT_PT][GMT->current.setting.proj_length_unit], + API->GMT->session.unit_name[API->GMT->current.setting.proj_length_unit], + y1-y0, (y1-y0)*GMT->session.u2u[GMT_PT][GMT->current.setting.proj_length_unit], + API->GMT->session.unit_name[API->GMT->current.setting.proj_length_unit]); } } if (fpb != NULL) { /* don't close twice */ - fclose (fpb); fpb = NULL; + fclose(fpb); fpb = NULL; } - if (!Ctrl->S.active && gmt_remove_file (GMT, BB_file)) { /* Remove the file with BB info */ - fclose (fp); fclose (fp2); + if (!Ctrl->S.active && gmt_remove_file(GMT, BB_file)) { /* Remove the file with BB info */ + fclose(fp); fclose(fp2); fp = fp2 = NULL; - Return (GMT_RUNTIME_ERROR); + Return(GMT_RUNTIME_ERROR); } - if (got_BB) GMT_Report (API, GMT_MSG_INFORMATION, "[%g %g %g %g]...\n", x0, y0, x1, y1); + if (got_BB) GMT_Report(API, GMT_MSG_INFORMATION, "[%g %g %g %g]...\n", x0, y0, x1, y1); } /* Open temporary file to be processed by Ghostscript. When -Te or -TE is used, tmp_file is for keeps */ if (Ctrl->T.eps) { - GMT_Report (API, GMT_MSG_INFORMATION, "Format EPS file...\n"); - if (Ctrl->D.active) sprintf (tmp_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ + GMT_Report(API, GMT_MSG_INFORMATION, "Format EPS file...\n"); + if (Ctrl->D.active) sprintf(tmp_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ if (!Ctrl->F.active || return_image) - strncat (tmp_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); + strncat(tmp_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); else - strcat (tmp_file, Ctrl->F.file); + strcat(tmp_file, Ctrl->F.file); if (strlen(tmp_file) < PATH_MAX-4) /* To please Coverity */ - strcat (tmp_file, ext[GS_DEV_EPS]); - if (!Ctrl->O.active && (fpo = fopen (tmp_file, "w")) == NULL) { - GMT_Report (API, GMT_MSG_ERROR, "Unable to open file %s for writing\n", tmp_file); + strcat(tmp_file, ext[GS_DEV_EPS]); + if (!Ctrl->O.active && (fpo = fopen(tmp_file, "w")) == NULL) { + GMT_Report(API, GMT_MSG_ERROR, "Unable to open file %s for writing\n", tmp_file); continue; } } else { if (GMT->current.setting.run_mode == GMT_MODERN) /* Place temporary EPS files in session dir */ - sprintf (tmp_file, "%s/psconvert_%dd.eps", API->gwf_dir, (int)getpid()); + sprintf(tmp_file, "%s/psconvert_%dd.eps", API->gwf_dir, (int)getpid()); else - sprintf (tmp_file, "%s/psconvert_%dd.eps", Ctrl->D.dir, (int)getpid()); - if (!Ctrl->O.active && (fpo = fopen (tmp_file, "w+")) == NULL) { - GMT_Report (API, GMT_MSG_ERROR, "Unable to create a temporary file\n"); + sprintf(tmp_file, "%s/psconvert_%dd.eps", Ctrl->D.dir, (int)getpid()); + if (!Ctrl->O.active && (fpo = fopen(tmp_file, "w+")) == NULL) { + GMT_Report(API, GMT_MSG_ERROR, "Unable to create a temporary file\n"); continue; } } @@ -2170,7 +2169,7 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { * Since we prefer the HiResBB over BB we must continue to read until both are found or 20 lines have past */ i = 0; - while ((psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF) && i < 20 && !(got_BB && got_HRBB && got_end)) { + while ((psconvert_file_line_reader(GMT, &line, &line_size, fp) != EOF) && i < 20 && !(got_BB && got_HRBB && got_end)) { i++; if (!line[0] || line[0] != '%') { /* Skip empty and non-comment lines */ } @@ -2199,8 +2198,19 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { } else if ((strstr(line, "%%Creator:")) && !strncmp(&line[11], "GMT", 3)) isGMT_PS = true; - else if ((strstr(line, "%%Orientation:")) &&!strncmp(&line[15], "Landscape", 9)) - landscape = landscape_orig = true; + else if ((strstr(line, "%%Orientation:")) &&!strncmp(&line[15], "Landscape", 9)) { + if (Ctrl->O.active && (Ctrl->P.active || Ctrl->A.crop)) { + /* The case here is that the on a first time all wet well, but on a second run the Orientation + was still Landscape and later on the w(idth) and h(eight) were swapped because they are set + after value that were edit by the first run. The trick is then to set the Orientation to + Portrait even before the rotation had been applied. + */ + landscape = landscape_orig = true; + fseek(fp, (off_t)-(strlen(line)+1), SEEK_CUR); /* Seek back to start of line */ + sprintf(line, "%%%%Orientation: Portrait \n"); + fprintf(fp, "%s", line); fflush(fp); + } + } else if ((strstr(line, "%%EndComments"))) got_end = true; if (got_BBatend == 1 && (got_end || i == 19)) { /* Now is the time to look at the end of the file */ @@ -2359,44 +2369,44 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { continue; } //else if (Ctrl->T.device == GS_DEV_PDF && !found_proj && !strncmp (&line[2], "PROJ", 4)) { - else if (!found_proj && !strncmp (&line[2], "PROJ", 4)) { + else if (!found_proj && !strncmp(&line[2], "PROJ", 4)) { /* Search for the PROJ tag in the ps file. Restrict the search for the PDF case as it's only used there. */ char *ptmp = NULL, xx1[128], xx2[128], yy1[128], yy2[128]; - sscanf (&line[8], "%s %s %s %s %s %s %s %s %s",proj4_name,xx1,xx2,yy1,yy2,c1,c2,c3,c4); - west = atof (c1); east = atof (c2); - south = atof (c3); north = atof (c4); - GMT->common.R.wesn[XLO] = atof (xx1); GMT->common.R.wesn[XHI] = atof (xx2); + sscanf(&line[8], "%s %s %s %s %s %s %s %s %s",proj4_name,xx1,xx2,yy1,yy2,c1,c2,c3,c4); + west = atof(c1); east = atof(c2); + south = atof(c3); north = atof(c4); + GMT->common.R.wesn[XLO] = atof(xx1); GMT->common.R.wesn[XHI] = atof(xx2); if (GMT->common.R.wesn[XLO] > 180.0 && GMT->common.R.wesn[XHI] > 180.0) { GMT->common.R.wesn[XLO] -= 360.0; GMT->common.R.wesn[XHI] -= 360.0; } - GMT->common.R.wesn[YLO] = atof (yy1); GMT->common.R.wesn[YHI] = atof (yy2); + GMT->common.R.wesn[YLO] = atof(yy1); GMT->common.R.wesn[YHI] = atof(yy2); found_proj = true; - if ((ptmp = strstr (&line[2], "+proj")) != NULL) { /* Search for the +proj in the comment line */ - proj4_cmd = strdup (&line[(int)(ptmp - &line[0])]); + if ((ptmp = strstr(&line[2], "+proj")) != NULL) { /* Search for the +proj in the comment line */ + proj4_cmd = strdup(&line[(int)(ptmp - &line[0])]); gmt_chop (proj4_cmd); /* Remove the new line char */ } - if (!strcmp (proj4_name,"latlong") || !strcmp (proj4_name,"xy")) { /* Linear case, use original coords */ + if (!strcmp(proj4_name,"latlong") || !strcmp(proj4_name,"xy")) { /* Linear case, use original coords */ west = atof(xx1); east = atof(xx2); south = atof(yy1); north = atof(yy2); /* One further test. +xy was found, but have we geog coords? Check that */ - if (!strcmp (proj4_name,"xy") && + if (!strcmp(proj4_name,"xy") && (west >= -180) && ((east <= 360) && ((east - west) <= 360)) && (south >= -90) && (north <= 90) ) { - proj4_cmd = strdup ("latlon"); - GMT_Report (API, GMT_MSG_INFORMATION, "An unknown psconvert setting was found but since " - "image coordinates seem to be geographical, a linear transformation " - "will be used.\n"); + proj4_cmd = strdup("latlon"); + GMT_Report(API, GMT_MSG_INFORMATION, "An unknown psconvert setting was found but since " + "image coordinates seem to be geographical, a linear transformation " + "will be used.\n"); } - else if (!strcmp (proj4_name,"xy") && Ctrl->W.warp) { - proj4_cmd = strdup ("xy"); - GMT_Report (API, GMT_MSG_DEBUG, "Requested an automatic geotiff generation, but " - "not sure a good psconvert option was used for the PS creation.\n"); + else if (!strcmp(proj4_name,"xy") && Ctrl->W.warp) { + proj4_cmd = strdup("xy"); + GMT_Report(API, GMT_MSG_DEBUG, "Requested an automatic geotiff generation, but " + "not sure a good psconvert option was used for the PS creation.\n"); } } else if (Ctrl->W.kml) { - GMT_Report (API, GMT_MSG_ERROR, "To GE images must be in geographical coordinates (-JXd projected). " - "Very likely this won't work as you wish inside GE.\n"); + GMT_Report(API, GMT_MSG_ERROR, "To GE images must be in geographical coordinates (-JXd projected). " + "Very likely this won't work as you wish inside GE.\n"); } } else if (!strncmp(line, "%GMTBoundingBox:", 16)) { @@ -2446,7 +2456,7 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { got_HRBB = false; continue; } - else if (Ctrl->P.active && landscape && !strncmp (line, "%%Orientation:", 14)) { + else if (Ctrl->P.active && landscape && !strncmp(line, "%%Orientation:", 14)) { fprintf(fpo, "%%%%Orientation: Portrait\n"); landscape = false; continue; @@ -2459,7 +2469,7 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { fprintf(fpo, "<< /PageSize [%g %g] >> setpagedevice\n", w, h); if (r != 0) fprintf(fpo, "%d rotate\n", r); - if (!gmt_M_is_zero (xt) || !gmt_M_is_zero (yt)) + if (!gmt_M_is_zero(xt) || !gmt_M_is_zero(yt)) fprintf(fpo, "%g %g translate\n", xt, yt); xt = yt = 0.0; r = 0; @@ -2533,72 +2543,72 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { else r_y = r_x; /* Not sure of this. Added later to shut up a compiler warning of r_y potentially used uninitialized */ - fprintf (fpo, "%% Recalculate translation and scale to obtain a resized image\n"); - fprintf (fpo, "%g %g translate\n", new_off_x, new_off_y); + fprintf(fpo, "%% Recalculate translation and scale to obtain a resized image\n"); + fprintf(fpo, "%g %g translate\n", new_off_x, new_off_y); if (landscape_orig) { - fprintf (fpo, "gsave %g %g translate 90 rotate %g %g scale\n", atof(t1)*r_x, atof(t2)*r_y, new_scale_x, new_scale_y); + fprintf(fpo, "gsave %g %g translate 90 rotate %g %g scale\n", atof(t1)*r_x, atof(t2)*r_y, new_scale_x, new_scale_y); } else - fprintf (fpo, "gsave %g %g scale\n", new_scale_x, new_scale_y); + fprintf(fpo, "gsave %g %g scale\n", new_scale_x, new_scale_y); set_background = false; add_grestore = true; - psconvert_possibly_fill_or_outline_BB (GMT, &(Ctrl->N), fpo); + psconvert_possibly_fill_or_outline_BB(GMT, &(Ctrl->N), fpo); } } else if (set_background) { /* Paint or outline the background rectangle. */ - if (!strncmp (line, "%%EndPageSetup", 14)) { + if (!strncmp(line, "%%EndPageSetup", 14)) { set_background = false; psconvert_possibly_fill_or_outline_BB (GMT, &(Ctrl->N), fpo); } } - else if (!strncmp (line, "%%Page:", 7)) { /* What is this for? */ + else if (!strncmp(line, "%%Page:", 7)) { /* What is this for? */ if (r != 0) - fprintf (fpo, "%d rotate\n", r); + fprintf(fpo, "%d rotate\n", r); if (!gmt_M_is_zero (xt) || !gmt_M_is_zero (yt)) - fprintf (fpo, "%g %g translate\n", xt, yt); + fprintf(fpo, "%g %g translate\n", xt, yt); xt = yt = 0.0; r = 0; } - else if (Ctrl->N.fade && !strncmp (line, "%%PageTrailer", 13) && Ctrl->N.fade_level > 0.0) { + else if (Ctrl->N.fade && !strncmp(line, "%%PageTrailer", 13) && Ctrl->N.fade_level > 0.0) { /* Place a transparent black rectangle over everything, at level of transparency */ - char *ptr = PSL_makecolor (GMT->PSL, Ctrl->N.fade_fill.rgb); - GMT_Report (API, GMT_MSG_INFORMATION, "Append fading to %s at %d%%.\n", gmt_putrgb (GMT, Ctrl->N.fade_fill.rgb), irint (100.0*Ctrl->N.fade_level)); - fprintf (fpo, "V clippath %s %g %g /Normal PSL_transp F N U\n", ptr, Ctrl->N.fade_level, Ctrl->N.fade_level); + char *ptr = PSL_makecolor(GMT->PSL, Ctrl->N.fade_fill.rgb); + GMT_Report(API, GMT_MSG_INFORMATION, "Append fading to %s at %d%%.\n", gmt_putrgb(GMT, Ctrl->N.fade_fill.rgb), irint (100.0*Ctrl->N.fade_level)); + fprintf(fpo, "V clippath %s %g %g /Normal PSL_transp F N U\n", ptr, Ctrl->N.fade_level, Ctrl->N.fade_level); transparency = true; } else if (Ctrl->T.device == GS_DEV_PDF && Ctrl->A.crop && found_proj && !strncmp(line, "%%PageTrailer", 13)) { /* This section is only needed when the output is PDF and adds GeoPDF tags. It is ignored when -! is active because then fpo == NUL */ - psconvert_file_line_reader (GMT, &line, &line_size, fp); - fprintf (fpo, "%%%%PageTrailer\n"); - fprintf (fpo, "%s\n", line); + psconvert_file_line_reader(GMT, &line, &line_size, fp); + fprintf(fpo, "%%%%PageTrailer\n"); + fprintf(fpo, "%s\n", line); if (Ctrl->Q.on[PSC_GEO]) { /* Write a GeoPDF registration info */ /* Allocate new control structures */ - to_gdalread = gmt_M_memory (GMT, NULL, 1, struct GMT_GDALREAD_IN_CTRL); - from_gdalread = gmt_M_memory (GMT, NULL, 1, struct GMT_GDALREAD_OUT_CTRL); + to_gdalread = gmt_M_memory(GMT, NULL, 1, struct GMT_GDALREAD_IN_CTRL); + from_gdalread = gmt_M_memory(GMT, NULL, 1, struct GMT_GDALREAD_OUT_CTRL); to_gdalread->W.active = true; from_gdalread->ProjRefPROJ4 = proj4_cmd; - gmt_gdalread (GMT, NULL, to_gdalread, from_gdalread); + gmt_gdalread(GMT, NULL, to_gdalread, from_gdalread); if (from_gdalread->ProjRefWKT != NULL) { char *new_wkt = NULL; - fprintf (fpo, "\n%% embed georegistation info\n"); - fprintf (fpo, "[ {ThisPage} <<\n"); - fprintf (fpo, "\t/VP [ <<\n"); - fprintf (fpo, "\t\t/Type /Viewport\n"); - fprintf (fpo, "\t\t/BBox[0 0 %g %g]\n", w, h); - fprintf (fpo, "\t\t/Measure <<\n"); - fprintf (fpo, "\t\t\t/Type /Measure\n"); - fprintf (fpo, "\t\t\t/Subtype /GEO\n"); - fprintf (fpo, "\t\t\t/Bounds[0 0 0 1 1 1 1 0]\n"); - fprintf (fpo, "\t\t\t/GPTS[%f %f %f %f %f %f %f %f]\n", - south, west, north, west, north, east, south, east); + fprintf(fpo, "\n%% embed georegistation info\n"); + fprintf(fpo, "[ {ThisPage} <<\n"); + fprintf(fpo, "\t/VP [ <<\n"); + fprintf(fpo, "\t\t/Type /Viewport\n"); + fprintf(fpo, "\t\t/BBox[0 0 %g %g]\n", w, h); + fprintf(fpo, "\t\t/Measure <<\n"); + fprintf(fpo, "\t\t\t/Type /Measure\n"); + fprintf(fpo, "\t\t\t/Subtype /GEO\n"); + fprintf(fpo, "\t\t\t/Bounds[0 0 0 1 1 1 1 0]\n"); + fprintf(fpo, "\t\t\t/GPTS[%f %f %f %f %f %f %f %f]\n", + south, west, north, west, north, east, south, east); if (gmtBB_width == 0) /* Older PS files that do not have yet the GMTBoundingBox */ - fprintf (fpo, "\t\t\t/LPTS[0 0 0 1 1 1 1 0]\n"); + fprintf(fpo, "\t\t\t/LPTS[0 0 0 1 1 1 1 0]\n"); else { /* Compute the LPTS. Takes the projected coordinate system into the page coordinate system */ double h0, v0, x1,x2,y1,y2; @@ -2610,40 +2620,40 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { x2 = gmtBB_width / w; x1 = 1 - x2; y2 = gmtBB_height / h; y1 = 1 - y2; } - fprintf (fpo, "\t\t\t/LPTS[%f %f %f %f %f %f %f %f]\n", x1,y1, x1,y2, x2,y2, x2,y1); + fprintf(fpo, "\t\t\t/LPTS[%f %f %f %f %f %f %f %f]\n", x1,y1, x1,y2, x2,y2, x2,y1); } - fprintf (fpo, "\t\t\t/GCS <<\n"); - fprintf (fpo, "\t\t\t\t/Type /PROJCS\n"); - fprintf (fpo, "\t\t\t\t/WKT\n"); + fprintf(fpo, "\t\t\t/GCS <<\n"); + fprintf(fpo, "\t\t\t\t/Type /PROJCS\n"); + fprintf(fpo, "\t\t\t\t/WKT\n"); new_wkt = gmt_strrep(from_gdalread->ProjRefWKT, "Mercator_1SP", "Mercator"); /* Because AR is dumb */ - fprintf (fpo, "\t\t\t\t(%s)\n", new_wkt); - fprintf (fpo, "\t\t\t>>\n"); - fprintf (fpo, "\t\t>>\n"); - fprintf (fpo, "\t>>]\n"); - fprintf (fpo, ">> /PUT pdfmark\n\n"); + fprintf(fpo, "\t\t\t\t(%s)\n", new_wkt); + fprintf(fpo, "\t\t\t>>\n"); + fprintf(fpo, "\t\t>>\n"); + fprintf(fpo, "\t>>]\n"); + fprintf(fpo, ">> /PUT pdfmark\n\n"); if (strlen(new_wkt) != strlen(from_gdalread->ProjRefWKT)) free(new_wkt); /* allocated in strrep */ } - gmt_M_free (GMT, to_gdalread); - gmt_M_free (GMT, from_gdalread); + gmt_M_free(GMT, to_gdalread); + gmt_M_free(GMT, from_gdalread); } continue; } - fprintf (fpo, "%s\n", line); + fprintf(fpo, "%s\n", line); } /* End while loop */ if (add_grestore) - fprintf (fpo, "grestore\n"); /* Since we started with gsave to change size */ + fprintf(fpo, "grestore\n"); /* Since we started with gsave to change size */ /* Recede a bit to test the contents of last line. -7 for when PS has CRLF endings */ - if (fseek (fp, (off_t)-7, SEEK_END)) - GMT_Report (API, GMT_MSG_ERROR, "Seeking to spot 7 bytes earlier failed\n"); + if (fseek(fp, (off_t)-7, SEEK_END)) + GMT_Report(API, GMT_MSG_ERROR, "Seeking to spot 7 bytes earlier failed\n"); /* Read until last line is encountered */ - while (psconvert_file_line_reader (GMT, &line, &line_size, fp) != EOF); - if (strncmp (line, "%%EOF", 5U)) /* Possibly a non-closed GMT PS file. To be confirmed later */ + while (psconvert_file_line_reader(GMT, &line, &line_size, fp) != EOF); + if (strncmp(line, "%%EOF", 5U)) /* Possibly a non-closed GMT PS file. To be confirmed later */ excessK = true; - fclose (fpo); fpo = NULL; - fclose (fp); fp = NULL; + fclose(fpo); fpo = NULL; + fclose(fp); fp = NULL; if (!Ctrl->O.active && Ctrl->T.ps && GMT->current.setting.run_mode == GMT_CLASSIC) { second_ps = true; /* Tell the renaming branch of modern mode to deal with this case too */ @@ -2656,9 +2666,9 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { } if (has_transparency && gsVersion.major == 9 && (gsVersion.minor == 51 || gsVersion.minor == 52)) - GMT_Report (API, GMT_MSG_WARNING, "Input file has transparency but your gs version %s has a bug preventing it - please upgrade to 9.53 or later\n", GSstring); + GMT_Report(API, GMT_MSG_WARNING, "Input file has transparency but your gs version %s has a bug preventing it - please upgrade to 9.53 or later\n", GSstring); if (transparency && Ctrl->T.device != GS_DEV_PDF) /* Must reset to PDF settings since we have transparency */ - gs_params = (psconvert_gs_is_good (gsVersion.major, gsVersion.minor)) ? gs_params_pdfnew : gs_params_pdfold; + gs_params = (psconvert_gs_is_good(gsVersion.major, gsVersion.minor)) ? gs_params_pdfnew : gs_params_pdfold; /* Build the converting Ghostscript command and execute it */ @@ -2667,28 +2677,28 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { int dest_device = Ctrl->T.device; /* Keep copy in case of temp change below */ double w_new, h_new; - strncpy (tag, &ext[Ctrl->T.device][1], 15U); - gmt_str_toupper (tag); + strncpy(tag, &ext[Ctrl->T.device][1], 15U); + gmt_str_toupper(tag); if (transparency) { /* Get here when PDF is _NOT_ the final output format but an intermediate format */ - GMT_Report (API, GMT_MSG_INFORMATION, "PS file with transparency must be converted to PDF before creating %s\n", tag); + GMT_Report(API, GMT_MSG_INFORMATION, "PS file with transparency must be converted to PDF before creating %s\n", tag); /* Temporarily change output device to PDF to get the PDF tmp file */ Ctrl->T.device = GS_DEV_PDF; /* After conversion, we convert the tmp PDF file to desired format via a 2nd gs call */ - GMT_Report (API, GMT_MSG_INFORMATION, "Convert to intermediate PDF...\n"); - strncat (out_file, ps_file, (size_t)pos_ext); - strcat (out_file, "_intermediate"); + GMT_Report(API, GMT_MSG_INFORMATION, "Convert to intermediate PDF...\n"); + strncat(out_file, ps_file, (size_t)pos_ext); + strcat(out_file, "_intermediate"); } else { /* Output is the final result */ - GMT_Report (API, GMT_MSG_INFORMATION, "Convert to %s...\n", tag); + GMT_Report(API, GMT_MSG_INFORMATION, "Convert to %s...\n", tag); - if (Ctrl->D.active) sprintf (out_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ + if (Ctrl->D.active) sprintf(out_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ if (!Ctrl->F.active || return_image) - strncat (out_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); + strncat(out_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); else - strcat (out_file, Ctrl->F.file); + strcat(out_file, Ctrl->F.file); } - strcat (out_file, ext[Ctrl->T.device]); + strcat(out_file, ext[Ctrl->T.device]); if (Ctrl->I.new_dpi_x) { /* We have a resize request (was Ctrl->I.resize = true;) */ w_new = w * Ctrl->I.new_dpi_x / 72.0; @@ -2697,89 +2707,88 @@ EXTERN_MSC int GMT_psconvert(void *V_API, int mode, void *args) { else { w_new = w * Ctrl->E.dpi / 72.0; h_new = h * Ctrl->E.dpi / 72.0; - } + if (Ctrl->A.round) { - pix_w = urint (w_new); - pix_h = urint (h_new); + pix_w = urint(w_new); + pix_h = urint(h_new); } else { - pix_w = urint (psconvert_smart_ceil (w_new)); - pix_h = urint (psconvert_smart_ceil (h_new)); + pix_w = urint(psconvert_smart_ceil(w_new)); + pix_h = urint(psconvert_smart_ceil(h_new)); } if (Ctrl->H.active) /* Rasterize at higher resolution, then downsample in gs */ - sprintf (resolution, "-g%dx%d -r%g -dDownScaleFactor=%d", pix_w * Ctrl->H.factor, pix_h * Ctrl->H.factor, Ctrl->E.dpi * Ctrl->H.factor, Ctrl->H.factor); + sprintf(resolution, "-g%dx%d -r%g -dDownScaleFactor=%d", pix_w * Ctrl->H.factor, pix_h * Ctrl->H.factor, Ctrl->E.dpi * Ctrl->H.factor, Ctrl->H.factor); else - sprintf (resolution, "-g%dx%d -r%g", pix_w, pix_h, Ctrl->E.dpi); + sprintf(resolution, "-g%dx%d -r%g", pix_w, pix_h, Ctrl->E.dpi); - sprintf (cmd, "%s%s %s %s%s -sDEVICE=%s %s %s -sOutputFile=%c%s%c %c%s%c", - at_sign, Ctrl->G.file, gs_params, Ctrl->C.arg, psconvert_alpha_bits(Ctrl), device[Ctrl->T.device], - device_options[Ctrl->T.device], resolution, quote, out_file, quote, quote, Ctrl->O.active ? ps_file : tmp_file, quote); + sprintf(cmd, "%s%s %s %s%s -sDEVICE=%s %s %s -sOutputFile=%c%s%c %c%s%c", + at_sign, Ctrl->G.file, gs_params, Ctrl->C.arg, psconvert_alpha_bits(Ctrl), device[Ctrl->T.device], + device_options[Ctrl->T.device], resolution, quote, out_file, quote, quote, Ctrl->O.active ? ps_file : tmp_file, quote); if (Ctrl->S.active) { /* Print Ghostscript command */ - API->print_func (GMT->session.std[GMT_ERR], cmd); - API->print_func (GMT->session.std[GMT_ERR], "\n"); + API->print_func(GMT->session.std[GMT_ERR], cmd); + API->print_func(GMT->session.std[GMT_ERR], "\n"); } /* Execute the Ghostscript command */ - GMT_Report (API, GMT_MSG_DEBUG, "Running: %s\n", cmd); + GMT_Report(API, GMT_MSG_DEBUG, "Running: %s\n", cmd); gmt_M_toc(GMT, ""); gmt_M_tic(GMT); /* Start timer to measure mostly the Ghostscript run time */ - sys_retval = system (cmd); + sys_retval = system(cmd); if (sys_retval) { - GMT_Report (API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); - gmt_remove_file (GMT, tmp_file); /* Since we created a temporary file from the memdata */ - Return (GMT_RUNTIME_ERROR); + GMT_Report(API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); + gmt_remove_file(GMT, tmp_file); /* Since we created a temporary file from the memdata */ + Return(GMT_RUNTIME_ERROR); } /* Check output file */ - if (access (out_file, R_OK)) { /* output file not created */ + if (access(out_file, R_OK)) { /* output file not created */ if (isGMT_PS && excessK) /* non-closed GMT input PS file */ - GMT_Report (API, GMT_MSG_ERROR, - "%s: GMT PS format detected but file is not finalized. Maybe a -K in excess? No output created.\n", ps_file); + GMT_Report(API, GMT_MSG_ERROR, + "%s: GMT PS format detected but file is not finalized. Maybe a -K in excess? No output created.\n", ps_file); else /* Either a bad closed GMT PS file or one of unknown origin */ - GMT_Report (API, GMT_MSG_ERROR, - "Could not create %s. Maybe input file does not fulfill PS specifications.\n", out_file); + GMT_Report(API, GMT_MSG_ERROR, + "Could not create %s. Maybe input file does not fulfill PS specifications.\n", out_file); } else { /* output file exists */ if (isGMT_PS && excessK) /* non-closed GMT input PS file */ - GMT_Report (API, GMT_MSG_ERROR, - "%s: GMT PS format detected but file is not finalized. Maybe a -K in excess? %s could be messed up.\n", - ps_file, out_file); + GMT_Report(API, GMT_MSG_ERROR, + "%s: GMT PS format detected but file is not finalized. Maybe a -K in excess? %s could be messed up.\n", + ps_file, out_file); /* else: Either a good closed GMT PS file or one of unknown origin */ } if (transparency) { /* Now convert temporary PDF to desired format */ char pdf_file[PATH_MAX] = {""}; - GMT_Report (API, GMT_MSG_INFORMATION, "Convert PDF with transparency to %s...\n", tag); + GMT_Report(API, GMT_MSG_INFORMATION, "Convert PDF with transparency to %s...\n", tag); Ctrl->T.device = dest_device; /* Reset output device type */ - strcpy (pdf_file, out_file); /* Now the PDF is the infile */ + strcpy(pdf_file, out_file); /* Now the PDF is the infile */ *out_file = '\0'; /* truncate string to build new output file */ - if (Ctrl->D.active) sprintf (out_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ + if (Ctrl->D.active) sprintf(out_file, "%s/", Ctrl->D.dir); /* Use specified output directory */ if (!Ctrl->F.active || return_image) - strncat (out_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); + strncat(out_file, &ps_file[pos_file], (size_t)(pos_ext - pos_file)); else - strcat (out_file, Ctrl->F.file); + strcat(out_file, Ctrl->F.file); - strcat (out_file, ext[Ctrl->T.device]); + strcat(out_file, ext[Ctrl->T.device]); /* After conversion, convert the tmp PDF file to desired format via a 2nd gs call */ - sprintf (cmd, "%s%s %s %s%s -sDEVICE=%s %s %s -sOutputFile=%c%s%c %c%s%c", - at_sign, Ctrl->G.file, gs_params, Ctrl->C.arg, psconvert_alpha_bits(Ctrl), device[Ctrl->T.device], - device_options[Ctrl->T.device], - resolution, quote, out_file, quote, quote, pdf_file, quote); + sprintf(cmd, "%s%s %s %s%s -sDEVICE=%s %s %s -sOutputFile=%c%s%c %c%s%c", + at_sign, Ctrl->G.file, gs_params, Ctrl->C.arg, psconvert_alpha_bits(Ctrl), device[Ctrl->T.device], + device_options[Ctrl->T.device], resolution, quote, out_file, quote, quote, pdf_file, quote); if (Ctrl->S.active) { /* Print 2nd Ghostscript command */ - API->print_func (GMT->session.std[GMT_ERR], cmd); - API->print_func (GMT->session.std[GMT_ERR], "\n"); + API->print_func(GMT->session.std[GMT_ERR], cmd); + API->print_func(GMT->session.std[GMT_ERR], "\n"); } /* Execute the 2nd Ghostscript command */ - GMT_Report (API, GMT_MSG_DEBUG, "Running: %s\n", cmd); - sys_retval = system (cmd); + GMT_Report(API, GMT_MSG_DEBUG, "Running: %s\n", cmd); + sys_retval = system(cmd); if (sys_retval) { - GMT_Report (API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); + GMT_Report(API, GMT_MSG_ERROR, "System call [%s] returned error %d.\n", cmd, sys_retval); Return (GMT_RUNTIME_ERROR); } - if (!Ctrl->S.active && gmt_remove_file (GMT, pdf_file)) /* The temporary PDF file is no longer needed */ + if (!Ctrl->S.active && gmt_remove_file(GMT, pdf_file)) /* The temporary PDF file is no longer needed */ Return (GMT_RUNTIME_ERROR); } }