comparison mupdf-source/thirdparty/leptonica/src/gplot.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27 /*!
28 * \file gplot.c
29 * <pre>
30 *
31 * Basic plotting functions
32 * GPLOT *gplotCreate()
33 * void gplotDestroy()
34 * l_int32 gplotAddPlot()
35 * l_int32 gplotSetScaling()
36 * PIX *gplotMakeOutputPix()
37 * l_int32 gplotMakeOutput()
38 * l_int32 gplotGenCommandFile()
39 * l_int32 gplotGenDataFiles()
40 *
41 * Quick, one-line plots
42 * l_int32 gplotSimple1()
43 * l_int32 gplotSimple2()
44 * l_int32 gplotSimpleN()
45 * PIX *gplotSimplePix1()
46 * PIX *gplotSimplePix2()
47 * PIX *gplotSimplePixN()
48 * GPLOT *gplotSimpleXY1()
49 * GPLOT *gplotSimpleXY2()
50 * GPLOT *gplotSimpleXYN()
51 * PIX *gplotGeneralPix1()
52 * PIX *gplotGeneralPix2()
53 * PIX *gplotGeneralPixN()
54 *
55 * Serialize for I/O
56 * GPLOT *gplotRead()
57 * l_int32 gplotWrite()
58 *
59 *
60 * Utility for programmatic plotting using gnuplot 4.6 or later
61 * Enabled:
62 * ~ output to png (color), ps and eps (mono), latex (mono)
63 * ~ optional title for plot
64 * ~ optional x and y axis labels
65 * ~ multiple plots on one frame
66 * ~ optional label for each plot on the frame
67 * ~ optional log scaling on either or both axes
68 * ~ choice of 5 plot styles for each array of input data
69 * ~ choice of 2 plot modes, either using one input array
70 * (Y vs index) or two input arrays (Y vs X). For functions
71 * that take two arrays, the first mode (Y vs index) is
72 * employed if the first array is NULL.
73 *
74 * General usage:
75 * gplotCreate() initializes for plotting
76 * gplotAddPlot() for each plot on the frame
77 * gplotMakeOutput() to generate all output files and run gnuplot
78 * gplotDestroy() to clean up
79 *
80 * Example of use:
81 * gplot = gplotCreate("tempskew", GPLOT_PNG, "Skew score vs angle",
82 * "angle (deg)", "score");
83 * gplotAddPlot(gplot, natheta, nascore1, GPLOT_LINES, "plot 1");
84 * gplotAddPlot(gplot, natheta, nascore2, GPLOT_POINTS, "plot 2");
85 * gplotSetScaling(gplot, GPLOT_LOG_SCALE_Y);
86 * gplotMakeOutput(gplot);
87 * gplotDestroy(&gplot);
88 *
89 * Example usage of one-line plot generators:
90 *
91 * -- Simple plots --
92 * Specify the root of output files, the output format,
93 * and the title (optional), but not the x and y coordinate labels
94 * or the plot labels. The plotstyle defaults to GPLOT_LINES.
95 * gplotSimple2(na1, na2, GPLOT_PNG, "/tmp/lept/histo/gray",
96 * "gray histogram");
97 * Multiple plots can be generated using gplotSimpleN().
98 *
99 * -- Simple plots with more options --
100 * Specify the root of output files, the plotstyle, the output format,
101 * and optionally the title, but not the x and y coordinate labels
102 * or the plot labels.
103 * gplotSimpleXY1(na1, na2, GPLOT_LINES, GPLOT_PNG,
104 * "/tmp/lept/histo/gray", "gray histogram");
105 * Multiple plots can be generated using gplotSimpleXYN().
106 *
107 * -- Simple plots returning a pix --
108 * Specify only the title (optional). The plotstyle defaults
109 * GPLOT_LINES and the output format is GPLOT_PNG..
110 * You can't specify the x and y coordinate labels or the plot label.
111 * The rootname of the generated files is determined internally.
112 * Pix *pix = gplotSimplePix2(na1, na2, "gray histogram");
113 * Multiple plots can be generated using gplotSimplePixN().
114 *
115 * -- General plots returning a pix --
116 * Specify the root of the output files, the plotstyle, and optionally
117 * the title and axis labels. This does not allow the individual
118 * plots to have plot labels, or to use different plotstyles
119 * for each plot.
120 * Pix *pix = gplotGeneralPix2(na1, na2, "/tmp/lept/histo/gray",
121 * GPLOT_LINES, "gray histogram",
122 * "pix value", "num pixels");
123 * Multiple plots can be generated using gplotGeneralPixN().
124 *
125 * Note for output to GPLOT_LATEX:
126 * This creates latex output of the plot, named <rootname>.tex.
127 * It needs to be placed in a latex file <latexname>.tex
128 * that precedes the plot output with, at a minimum:
129 * \documentclass{article}
130 * \begin{document}
131 * and ends with
132 * \end{document}
133 * You can then generate a dvi file <latexname>.dvi using
134 * latex <latexname>.tex
135 * a PostScript file <psname>.ps from that using
136 * dvips -o <psname>.ps <latexname>.dvi
137 * and pdf file <psname>.pdf from that using Ghostscript's ps2pdf:
138 * ps2pdf <psname>.ps <pdfname>.pdf
139 *
140 * N.B. To generate plots:
141 * (1) It is necessary to have gnuplot installed on your Unix system,
142 * or wgnuplot on Windows.
143 * (2) You must enable debug operations:
144 * setLeptDebugOK(1);
145 * </pre>
146 */
147
148 #ifdef HAVE_CONFIG_H
149 #include <config_auto.h>
150 #endif /* HAVE_CONFIG_H */
151
152 #include <string.h>
153 #include "allheaders.h"
154
155 #define Bufsize 512 /* hardcoded below in fscanf */
156
157 const char *gplotstylenames[] = {"with lines",
158 "with points",
159 "with impulses",
160 "with linespoints",
161 "with dots"};
162 const char *gplotfileoutputs[] = {"",
163 "PNG",
164 "PS",
165 "EPS",
166 "LATEX",
167 "PNM"};
168
169
170 /*-----------------------------------------------------------------*
171 * Basic Plotting Functions *
172 *-----------------------------------------------------------------*/
173 /*!
174 * \brief gplotCreate()
175 *
176 * \param[in] rootname root for all output files
177 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS,
178 * GPLOT_LATEX, GPLOT_PNM
179 * \param[in] title [optional] overall title
180 * \param[in] xlabel [optional] x axis label
181 * \param[in] ylabel [optional] y axis label
182 * \return gplot, or NULL on error
183 *
184 * <pre>
185 * Notes:
186 * (1) This initializes the plot.
187 * (2) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
188 * double quotes and backquotes, but not single quotes.
189 * </pre>
190 */
191 GPLOT *
192 gplotCreate(const char *rootname,
193 l_int32 outformat,
194 const char *title,
195 const char *xlabel,
196 const char *ylabel)
197 {
198 char *newroot;
199 char buf[Bufsize];
200 l_int32 badchar;
201 GPLOT *gplot;
202
203 if (!rootname)
204 return (GPLOT *)ERROR_PTR("rootname not defined", __func__, NULL);
205 if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
206 outformat != GPLOT_EPS && outformat != GPLOT_LATEX &&
207 outformat != GPLOT_PNM)
208 return (GPLOT *)ERROR_PTR("outformat invalid", __func__, NULL);
209 stringCheckForChars(rootname, "`;&|><\"?*$()", &badchar);
210 if (badchar) /* danger of command injection */
211 return (GPLOT *)ERROR_PTR("invalid rootname", __func__, NULL);
212
213 #if !defined(HAVE_LIBPNG)
214 if (outformat == GPLOT_PNG) {
215 L_WARNING("png library missing; output pnm format\n", __func__);
216 outformat = GPLOT_PNM;
217 }
218 #endif
219
220 gplot = (GPLOT *)LEPT_CALLOC(1, sizeof(GPLOT));
221 gplot->cmddata = sarrayCreate(0);
222 gplot->datanames = sarrayCreate(0);
223 gplot->plotdata = sarrayCreate(0);
224 gplot->plotlabels = sarrayCreate(0);
225 gplot->plotstyles = numaCreate(0);
226
227 /* Save title, labels, rootname, outformat, cmdname, outname */
228 newroot = genPathname(rootname, NULL);
229 gplot->rootname = newroot;
230 gplot->outformat = outformat;
231 snprintf(buf, Bufsize, "%s.cmd", rootname);
232 gplot->cmdname = stringNew(buf);
233 if (outformat == GPLOT_PNG)
234 snprintf(buf, Bufsize, "%s.png", newroot);
235 else if (outformat == GPLOT_PS)
236 snprintf(buf, Bufsize, "%s.ps", newroot);
237 else if (outformat == GPLOT_EPS)
238 snprintf(buf, Bufsize, "%s.eps", newroot);
239 else if (outformat == GPLOT_LATEX)
240 snprintf(buf, Bufsize, "%s.tex", newroot);
241 else if (outformat == GPLOT_PNM)
242 snprintf(buf, Bufsize, "%s.pnm", newroot);
243 gplot->outname = stringNew(buf);
244 if (title) gplot->title = stringNew(title);
245 if (xlabel) gplot->xlabel = stringNew(xlabel);
246 if (ylabel) gplot->ylabel = stringNew(ylabel);
247
248 return gplot;
249 }
250
251
252 /*!
253 * \brief gplotDestroy()
254 *
255 * \param[in,out] pgplot will be set to null before returning
256 */
257 void
258 gplotDestroy(GPLOT **pgplot)
259 {
260 GPLOT *gplot;
261
262 if (pgplot == NULL) {
263 L_WARNING("ptr address is null!\n", __func__);
264 return;
265 }
266
267 if ((gplot = *pgplot) == NULL)
268 return;
269
270 LEPT_FREE(gplot->rootname);
271 LEPT_FREE(gplot->cmdname);
272 sarrayDestroy(&gplot->cmddata);
273 sarrayDestroy(&gplot->datanames);
274 sarrayDestroy(&gplot->plotdata);
275 sarrayDestroy(&gplot->plotlabels);
276 numaDestroy(&gplot->plotstyles);
277 LEPT_FREE(gplot->outname);
278 if (gplot->title)
279 LEPT_FREE(gplot->title);
280 if (gplot->xlabel)
281 LEPT_FREE(gplot->xlabel);
282 if (gplot->ylabel)
283 LEPT_FREE(gplot->ylabel);
284
285 LEPT_FREE(gplot);
286 *pgplot = NULL;
287 }
288
289
290 /*!
291 * \brief gplotAddPlot()
292 *
293 * \param[in] gplot
294 * \param[in] nax [optional] numa: set to null for Y_VS_I;
295 * required for Y_VS_X
296 * \param[in] nay numa; required for both Y_VS_I and Y_VS_X
297 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
298 * GPLOT_LINESPOINTS, GPLOT_DOTS
299 * \param[in] plotlabel [optional] label for individual plot
300 * \return 0 if OK, 1 on error
301 *
302 * <pre>
303 * Notes:
304 * (1) There are 2 options for (x,y) values:
305 * o To plot an array vs a linear function of the
306 * index, set %nax = NULL.
307 * o To plot one array vs another, use both %nax and %nay.
308 * (2) If %nax is NULL, the x value corresponding to the i-th
309 * value of %nay is found from the startx and delx fields
310 * in %nay:
311 * x = startx + i * delx
312 * These are set with numaSetParameters(). Their default
313 * values are startx = 0.0, delx = 1.0.
314 * (3) If %nax is defined, it must be the same size as %nay, and
315 * must have at least one number.
316 * (4) The 'plotlabel' string can have spaces, double
317 * quotes and backquotes, but not single quotes.
318 * </pre>
319 */
320 l_ok
321 gplotAddPlot(GPLOT *gplot,
322 NUMA *nax,
323 NUMA *nay,
324 l_int32 plotstyle,
325 const char *plotlabel)
326 {
327 char buf[Bufsize];
328 char emptystring[] = "";
329 char *datastr, *title;
330 l_int32 n, i;
331 l_float32 valx, valy, startx, delx;
332 SARRAY *sa;
333
334 if (!gplot)
335 return ERROR_INT("gplot not defined", __func__, 1);
336 if (!nay)
337 return ERROR_INT("nay not defined", __func__, 1);
338 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
339 return ERROR_INT("invalid plotstyle", __func__, 1);
340
341 if ((n = numaGetCount(nay)) == 0)
342 return ERROR_INT("no points to plot", __func__, 1);
343 if (nax && (n != numaGetCount(nax)))
344 return ERROR_INT("nax and nay sizes differ", __func__, 1);
345 if (n == 1 && plotstyle == GPLOT_LINES) {
346 L_INFO("only 1 pt; changing style to points\n", __func__);
347 plotstyle = GPLOT_POINTS;
348 }
349
350 /* Save plotstyle and plotlabel */
351 numaGetParameters(nay, &startx, &delx);
352 numaAddNumber(gplot->plotstyles, plotstyle);
353 if (plotlabel) {
354 title = stringNew(plotlabel);
355 sarrayAddString(gplot->plotlabels, title, L_INSERT);
356 } else {
357 sarrayAddString(gplot->plotlabels, emptystring, L_COPY);
358 }
359
360 /* Generate and save data filename */
361 gplot->nplots++;
362 snprintf(buf, Bufsize, "%s.data.%d", gplot->rootname, gplot->nplots);
363 sarrayAddString(gplot->datanames, buf, L_COPY);
364
365 /* Generate data and save as a string */
366 sa = sarrayCreate(n);
367 for (i = 0; i < n; i++) {
368 if (nax)
369 numaGetFValue(nax, i, &valx);
370 else
371 valx = startx + i * delx;
372 numaGetFValue(nay, i, &valy);
373 snprintf(buf, Bufsize, "%f %f\n", valx, valy);
374 sarrayAddString(sa, buf, L_COPY);
375 }
376 datastr = sarrayToString(sa, 0);
377 sarrayAddString(gplot->plotdata, datastr, L_INSERT);
378 sarrayDestroy(&sa);
379
380 return 0;
381 }
382
383
384 /*!
385 * \brief gplotSetScaling()
386 *
387 * \param[in] gplot
388 * \param[in] scaling GPLOT_LINEAR_SCALE, GPLOT_LOG_SCALE_X,
389 * GPLOT_LOG_SCALE_Y, GPLOT_LOG_SCALE_X_Y
390 * \return 0 if OK; 1 on error
391 *
392 * <pre>
393 * Notes:
394 * (1) By default, the x and y axis scaling is linear.
395 * (2) Call this function to set semi-log or log-log scaling.
396 * </pre>
397 */
398 l_ok
399 gplotSetScaling(GPLOT *gplot,
400 l_int32 scaling)
401 {
402 if (!gplot)
403 return ERROR_INT("gplot not defined", __func__, 1);
404 if (scaling != GPLOT_LINEAR_SCALE &&
405 scaling != GPLOT_LOG_SCALE_X &&
406 scaling != GPLOT_LOG_SCALE_Y &&
407 scaling != GPLOT_LOG_SCALE_X_Y)
408 return ERROR_INT("invalid gplot scaling", __func__, 1);
409 gplot->scaling = scaling;
410 return 0;
411 }
412
413
414 /*!
415 * \brief gplotMakeOutputPix()
416 *
417 * \param[in] gplot
418 * \return 0 if OK; 1 on error
419 *
420 * <pre>
421 * Notes:
422 * (1) This wraps gplotMakeOutput(), and returns a pix.
423 * See gplotMakeOutput() for details.
424 * (2) The gplot output format must be an image (png or pnm).
425 * </pre>
426 */
427 PIX *
428 gplotMakeOutputPix(GPLOT *gplot)
429 {
430 if (!gplot)
431 return (PIX *)ERROR_PTR("gplot not defined", __func__, NULL);
432 if (gplot->outformat != GPLOT_PNG && gplot->outformat != GPLOT_PNM)
433 return (PIX *)ERROR_PTR("output format not an image", __func__, NULL);
434
435 if (gplotMakeOutput(gplot))
436 return (PIX *)ERROR_PTR("plot output not made", __func__, NULL);
437 return pixRead(gplot->outname);
438 }
439
440
441 /*!
442 * \brief gplotMakeOutput()
443 *
444 * \param[in] gplot
445 * \return 0 if OK; 1 on error
446 *
447 * <pre>
448 * Notes:
449 * (1) This uses gplot and the new arrays to add a plot
450 * to the output, by writing a new data file and appending
451 * the appropriate plot commands to the command file.
452 * (2) Along with gplotMakeOutputPix(), these are the only functions
453 * in this file that requires the gnuplot executable to
454 * actually generate the plot.
455 * (3) The command file name for unix is canonical (i.e., directory /tmp)
456 * but the temp filename paths in the command file must be correct.
457 * (4) The gnuplot program for Windows is wgnuplot.exe.
458 * </pre>
459 */
460 l_ok
461 gplotMakeOutput(GPLOT *gplot)
462 {
463 char buf[Bufsize];
464 char *cmdname;
465
466 if (!gplot)
467 return ERROR_INT("gplot not defined", __func__, 1);
468
469 if (!LeptDebugOK) {
470 L_INFO("running gnuplot is disabled; "
471 "use setLeptDebugOK(1) to enable\n", __func__);
472 return 0;
473 }
474
475 #ifdef OS_IOS /* iOS 11 does not support system() */
476 return ERROR_INT("iOS 11 does not support system()", __func__, 0);
477 #endif /* OS_IOS */
478
479 gplotGenCommandFile(gplot);
480 gplotGenDataFiles(gplot);
481 cmdname = genPathname(gplot->cmdname, NULL);
482
483 #ifndef _WIN32
484 snprintf(buf, Bufsize, "gnuplot %s", cmdname);
485 #else
486 snprintf(buf, Bufsize, "wgnuplot %s", cmdname);
487 #endif /* _WIN32 */
488
489 callSystemDebug(buf); /* gnuplot || wgnuplot */
490 LEPT_FREE(cmdname);
491 return 0;
492 }
493
494
495 /*!
496 * \brief gplotGenCommandFile()
497 *
498 * \param[in] gplot
499 * \return 0 if OK, 1 on error
500 */
501 l_ok
502 gplotGenCommandFile(GPLOT *gplot)
503 {
504 char buf[Bufsize];
505 char *cmdstr, *plotlabel, *dataname;
506 l_int32 i, plotstyle, nplots;
507 FILE *fp;
508
509 if (!gplot)
510 return ERROR_INT("gplot not defined", __func__, 1);
511
512 /* Remove any previous command data */
513 sarrayClear(gplot->cmddata);
514
515 /* Generate command data instructions */
516 if (gplot->title) { /* set title */
517 snprintf(buf, Bufsize, "set title '%s'", gplot->title);
518 sarrayAddString(gplot->cmddata, buf, L_COPY);
519 }
520 if (gplot->xlabel) { /* set xlabel */
521 snprintf(buf, Bufsize, "set xlabel '%s'", gplot->xlabel);
522 sarrayAddString(gplot->cmddata, buf, L_COPY);
523 }
524 if (gplot->ylabel) { /* set ylabel */
525 snprintf(buf, Bufsize, "set ylabel '%s'", gplot->ylabel);
526 sarrayAddString(gplot->cmddata, buf, L_COPY);
527 }
528
529 /* Set terminal type and output */
530 if (gplot->outformat == GPLOT_PNG) {
531 snprintf(buf, Bufsize, "set terminal png; set output '%s'",
532 gplot->outname);
533 } else if (gplot->outformat == GPLOT_PS) {
534 snprintf(buf, Bufsize, "set terminal postscript; set output '%s'",
535 gplot->outname);
536 } else if (gplot->outformat == GPLOT_EPS) {
537 snprintf(buf, Bufsize, "set terminal postscript eps; set output '%s'",
538 gplot->outname);
539 } else if (gplot->outformat == GPLOT_LATEX) {
540 snprintf(buf, Bufsize, "set terminal latex; set output '%s'",
541 gplot->outname);
542 } else if (gplot->outformat == GPLOT_PNM) {
543 snprintf(buf, Bufsize, "set terminal pbm color; set output '%s'",
544 gplot->outname);
545 }
546 sarrayAddString(gplot->cmddata, buf, L_COPY);
547
548 if (gplot->scaling == GPLOT_LOG_SCALE_X ||
549 gplot->scaling == GPLOT_LOG_SCALE_X_Y) {
550 snprintf(buf, Bufsize, "set logscale x");
551 sarrayAddString(gplot->cmddata, buf, L_COPY);
552 }
553 if (gplot->scaling == GPLOT_LOG_SCALE_Y ||
554 gplot->scaling == GPLOT_LOG_SCALE_X_Y) {
555 snprintf(buf, Bufsize, "set logscale y");
556 sarrayAddString(gplot->cmddata, buf, L_COPY);
557 }
558
559 nplots = sarrayGetCount(gplot->datanames);
560 for (i = 0; i < nplots; i++) {
561 plotlabel = sarrayGetString(gplot->plotlabels, i, L_NOCOPY);
562 dataname = sarrayGetString(gplot->datanames, i, L_NOCOPY);
563 numaGetIValue(gplot->plotstyles, i, &plotstyle);
564 if (nplots == 1) {
565 snprintf(buf, Bufsize, "plot '%s' title '%s' %s",
566 dataname, plotlabel, gplotstylenames[plotstyle]);
567 } else {
568 if (i == 0)
569 snprintf(buf, Bufsize, "plot '%s' title '%s' %s, \\",
570 dataname, plotlabel, gplotstylenames[plotstyle]);
571 else if (i < nplots - 1)
572 snprintf(buf, Bufsize, " '%s' title '%s' %s, \\",
573 dataname, plotlabel, gplotstylenames[plotstyle]);
574 else
575 snprintf(buf, Bufsize, " '%s' title '%s' %s",
576 dataname, plotlabel, gplotstylenames[plotstyle]);
577 }
578 sarrayAddString(gplot->cmddata, buf, L_COPY);
579 }
580
581 /* Write command data to file */
582 cmdstr = sarrayToString(gplot->cmddata, 1);
583 if ((fp = fopenWriteStream(gplot->cmdname, "w")) == NULL) {
584 L_ERROR("stream not opened for command: %s\n", __func__, cmdstr);
585 LEPT_FREE(cmdstr);
586 return 1;
587 }
588 fwrite(cmdstr, 1, strlen(cmdstr), fp);
589 fclose(fp);
590 LEPT_FREE(cmdstr);
591 return 0;
592 }
593
594
595 /*!
596 * \brief gplotGenDataFiles()
597 *
598 * \param[in] gplot
599 * \return 0 if OK, 1 on error
600 *
601 * <pre>
602 * Notes:
603 * (1) The pathnames in the gplot command file are actual pathnames,
604 * which can be in temp directories. Consequently, they must not be
605 * rewritten by calling fopenWriteStream(), and we use fopen().
606 * </pre>
607 */
608 l_ok
609 gplotGenDataFiles(GPLOT *gplot)
610 {
611 char *plotdata, *dataname;
612 l_int32 i, nplots;
613 FILE *fp;
614
615 if (!gplot)
616 return ERROR_INT("gplot not defined", __func__, 1);
617
618 nplots = sarrayGetCount(gplot->datanames);
619 for (i = 0; i < nplots; i++) {
620 plotdata = sarrayGetString(gplot->plotdata, i, L_NOCOPY);
621 dataname = sarrayGetString(gplot->datanames, i, L_NOCOPY);
622 if ((fp = fopen(dataname, "w")) == NULL)
623 return ERROR_INT_1("datafile stream not opened",
624 dataname, __func__, 1);
625 fwrite(plotdata, 1, strlen(plotdata), fp);
626 fclose(fp);
627 }
628
629 return 0;
630 }
631
632
633 /*-----------------------------------------------------------------*
634 * Quick one-line plots *
635 *-----------------------------------------------------------------*/
636 /*!
637 * \brief gplotSimple1()
638 *
639 * \param[in] na numa; plot Y_VS_I
640 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS,
641 * GPLOT_LATEX, GPLOT_PNM
642 * \param[in] outroot root of output files
643 * \param[in] title [optional], can be NULL
644 * \return 0 if OK, 1 on error
645 *
646 * <pre>
647 * Notes:
648 * (1) This generates a line plot of a numa, where the array value
649 * is plotted vs the array index. The plot is generated
650 * in the specified output format; the title is optional.
651 * (2) When calling these simple plot functions more than once, use
652 * different %outroot to avoid overwriting the output files.
653 * </pre>
654 */
655 l_ok
656 gplotSimple1(NUMA *na,
657 l_int32 outformat,
658 const char *outroot,
659 const char *title)
660 {
661 GPLOT *gplot;
662
663 gplot = gplotSimpleXY1(NULL, na, GPLOT_LINES, outformat, outroot, title);
664 if (!gplot)
665 return ERROR_INT("failed to generate plot", __func__, 1);
666 gplotDestroy(&gplot);
667 return 0;
668 }
669
670
671 /*!
672 * \brief gplotSimple2()
673 *
674 * \param[in] na1 numa; plot with Y_VS_I
675 * \param[in] na2 ditto
676 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS,
677 * GPLOT_LATEX, GPLOT_PNM
678 * \param[in] outroot root of output files
679 * \param[in] title [optional]
680 * \return 0 if OK, 1 on error
681 *
682 * <pre>
683 * Notes:
684 * (1) This generates a line plot of two numa, where the array values
685 * are each plotted vs the array index. The plot is generated
686 * in the specified output format; the title is optional.
687 * (2) When calling these simple plot functions more than once, use
688 * different %outroot to avoid overwriting the output files.
689 * </pre>
690 */
691 l_ok
692 gplotSimple2(NUMA *na1,
693 NUMA *na2,
694 l_int32 outformat,
695 const char *outroot,
696 const char *title)
697 {
698 GPLOT *gplot;
699
700 gplot = gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES,
701 outformat, outroot, title);
702 if (!gplot)
703 return ERROR_INT("failed to generate plot", __func__, 1);
704 gplotDestroy(&gplot);
705 return 0;
706 }
707
708
709 /*!
710 * \brief gplotSimpleN()
711 *
712 * \param[in] naa numaa; plot Y_VS_I for each numa
713 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS,
714 * GPLOT_LATEX, GPLOT_PNM
715 * \param[in] outroot root of output files
716 * \param[in] title [optional]
717 * \return 0 if OK, 1 on error
718 *
719 * <pre>
720 * Notes:
721 * (1) This generates a line plot of all numas in a numaa (array of numa),
722 * where the array values are each plotted vs the array index.
723 * The plot is generated in the specified output format;
724 * the title is optional.
725 * (2) When calling these simple plot functions more than once, use
726 * different %outroot to avoid overwriting the output files.
727 * </pre>
728 */
729 l_ok
730 gplotSimpleN(NUMAA *naa,
731 l_int32 outformat,
732 const char *outroot,
733 const char *title)
734 {
735 GPLOT *gplot;
736
737 gplot = gplotSimpleXYN(NULL, naa, GPLOT_LINES, outformat, outroot, title);
738 if (!gplot)
739 return ERROR_INT("failed to generate plot", __func__, 1);
740 gplotDestroy(&gplot);
741 return 0;
742 }
743
744
745 /*!
746 * \brief gplotSimplePix1()
747 *
748 * \param[in] na numa; plot Y_VS_I
749 * \param[in] title [optional], can be NULL
750 * \return pix of plot, or null on error
751 *
752 * <pre>
753 * Notes:
754 * (1) This generates a line plot of a numa as a pix, where the array
755 * value is plotted vs the array index. The title is optional.
756 * (2) The temporary plot file is a png; its name is generated internally
757 * and stored in gplot.
758 * </pre>
759 */
760 PIX *
761 gplotSimplePix1(NUMA *na,
762 const char *title)
763 {
764 char buf[64];
765 static l_atomic index;
766 GPLOT *gplot;
767 PIX *pix;
768
769 if (!na)
770 return (PIX *)ERROR_PTR("na not defined", __func__, NULL);
771
772 lept_mkdir("lept/gplot/pix");
773 snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pix1.%d", index++);
774 gplot = gplotSimpleXY1(NULL, na, GPLOT_LINES, GPLOT_PNG, buf, title);
775 if (!gplot)
776 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL);
777 pix = pixRead(gplot->outname);
778 gplotDestroy(&gplot);
779 if (!pix)
780 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL);
781 return pix;
782 }
783
784
785 /*!
786 * \brief gplotSimplePix2()
787 *
788 * \param[in] na1 numa; plot with Y_VS_I
789 * \param[in] na2 ditto
790 * \param[in] title [optional], can be NULL
791 * \return pix of plot, or null on error
792 *
793 * <pre>
794 * Notes:
795 * (1) This generates a pix with line plots of two numa, where each of
796 * two arrays is plotted vs the array index. the title is optional.
797 * (2) The temporary plot file is a png; its name is generated internally
798 * and stored in gplot.
799 * </pre>
800 */
801 PIX *
802 gplotSimplePix2(NUMA *na1,
803 NUMA *na2,
804 const char *title)
805 {
806 char buf[64];
807 static l_atomic index;
808 GPLOT *gplot;
809 PIX *pix;
810
811 if (!na1 || !na2)
812 return (PIX *)ERROR_PTR("both na1, na2 not defined", __func__, NULL);
813
814 lept_mkdir("lept/gplot/pix");
815 snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pix2.%d", index++);
816 gplot = gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES, GPLOT_PNG, buf, title);
817 if (!gplot)
818 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL);
819 pix = pixRead(gplot->outname);
820 gplotDestroy(&gplot);
821 if (!pix)
822 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL);
823 return pix;
824 }
825
826
827 /*!
828 * \brief gplotSimplePixN()
829 *
830 * \param[in] naa numaa; plot Y_VS_I for each numa
831 * \param[in] title [optional], can be NULL
832 * \return pix of plot, or null on error
833 *
834 * <pre>
835 * Notes:
836 * (1) This generates a pix with an arbitrary number of line plots,
837 * each coming from a numa in %naa. Each array value is plotted
838 * vs the array index. The title is optional.
839 * (2) The temporary plot file is a png; its name is generated internally
840 * and stored in gplot.
841 * </pre>
842 */
843 PIX *
844 gplotSimplePixN(NUMAA *naa,
845 const char *title)
846 {
847 char buf[64];
848 static l_atomic index;
849 GPLOT *gplot;
850 PIX *pix;
851
852 if (!naa)
853 return (PIX *)ERROR_PTR("naa not defined", __func__, NULL);
854
855 lept_mkdir("lept/gplot/pix");
856 snprintf(buf, sizeof(buf), "/tmp/lept/gplot/pixN.%d", index++);
857 gplot = gplotSimpleXYN(NULL, naa, GPLOT_LINES, GPLOT_PNG, buf, title);
858 if (!gplot)
859 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL);
860 pix = pixRead(gplot->outname);
861 gplotDestroy(&gplot);
862 if (!pix)
863 return (PIX *)ERROR_PTR("failed to generate plot", __func__, NULL);
864 return pix;
865 }
866
867
868 /*!
869 * \brief gplotSimpleXY1()
870 *
871 * \param[in] nax [optional]
872 * \param[in] nay [required]
873 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
874 * GPLOT_LINESPOINTS, GPLOT_DOTS
875 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS,
876 * GPLOT_LATEX, GPLOT_PNM
877 * \param[in] outroot root of output files
878 * \param[in] title [optional], can be NULL
879 * \return gplot or null on error
880 *
881 * <pre>
882 * Notes:
883 * (1) This generates a plot of a %nay vs %nax, generated in
884 * the specified output format. The title is optional.
885 * (2) Use 0 for default plotstyle (lines).
886 * (3) %nax is optional. If NULL, %nay is plotted against
887 * the array index.
888 * (4) When calling these simple plot functions more than once, use
889 * different %outroot to avoid overwriting the output files.
890 * (5) The returned gplot must be destroyed by the caller.
891 * </pre>
892 */
893 GPLOT *
894 gplotSimpleXY1(NUMA *nax,
895 NUMA *nay,
896 l_int32 plotstyle,
897 l_int32 outformat,
898 const char *outroot,
899 const char *title)
900 {
901 GPLOT *gplot;
902
903 if (!nay)
904 return (GPLOT *)ERROR_PTR("nay not defined", __func__, NULL);
905 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
906 return (GPLOT *)ERROR_PTR("invalid plotstyle", __func__, NULL);
907 if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
908 outformat != GPLOT_EPS && outformat != GPLOT_LATEX &&
909 outformat != GPLOT_PNM)
910 return (GPLOT *)ERROR_PTR("invalid outformat", __func__, NULL);
911 if (!outroot)
912 return (GPLOT *)ERROR_PTR("outroot not specified", __func__, NULL);
913
914 if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
915 return (GPLOT *)ERROR_PTR("gplot not made", __func__, NULL);
916 gplotAddPlot(gplot, nax, nay, plotstyle, NULL);
917 gplotMakeOutput(gplot);
918 return gplot;
919 }
920
921
922 /*!
923 * \brief gplotSimpleXY2()
924 *
925 * \param[in] nax [optional], can be NULL
926 * \param[in] nay1
927 * \param[in] nay2
928 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
929 * GPLOT_LINESPOINTS, GPLOT_DOTS
930 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS,
931 * GPLOT_LATEX, GPLOT_PNM
932 * \param[in] outroot root of output files
933 * \param[in] title [optional]
934 * \return gplot or null on error
935 *
936 * <pre>
937 * Notes:
938 * (1) This generates plots of %nay1 and %nay2 against %nax, generated
939 * in the specified output format. The title is optional.
940 * (2) Use 0 for default plotstyle (lines).
941 * (3) %nax is optional. If NULL, %nay1 and %nay2 are plotted
942 * against the array index.
943 * (4) When calling these simple plot functions more than once, use
944 * different %outroot to avoid overwriting the output files.
945 * (5) The returned gplot must be destroyed by the caller.
946 * </pre>
947 */
948 GPLOT *
949 gplotSimpleXY2(NUMA *nax,
950 NUMA *nay1,
951 NUMA *nay2,
952 l_int32 plotstyle,
953 l_int32 outformat,
954 const char *outroot,
955 const char *title)
956 {
957 GPLOT *gplot;
958
959 if (!nay1 || !nay2)
960 return (GPLOT *)ERROR_PTR("nay1 and nay2 not both defined",
961 __func__, NULL);
962 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
963 return (GPLOT *)ERROR_PTR("invalid plotstyle", __func__, NULL);
964 if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
965 outformat != GPLOT_EPS && outformat != GPLOT_LATEX &&
966 outformat != GPLOT_PNM)
967 return (GPLOT *)ERROR_PTR("invalid outformat", __func__, NULL);
968 if (!outroot)
969 return (GPLOT *)ERROR_PTR("outroot not specified", __func__, NULL);
970
971 if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
972 return (GPLOT *)ERROR_PTR("gplot not made", __func__, NULL);
973 gplotAddPlot(gplot, nax, nay1, plotstyle, NULL);
974 gplotAddPlot(gplot, nax, nay2, plotstyle, NULL);
975 gplotMakeOutput(gplot);
976 return gplot;
977 }
978
979
980 /*!
981 * \brief gplotSimpleXYN()
982 *
983 * \param[in] nax [optional]; can be NULL
984 * \param[in] naay numaa of arrays to plot against %nax
985 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
986 * GPLOT_LINESPOINTS, GPLOT_DOTS
987 * \param[in] outformat GPLOT_PNG, GPLOT_PS, GPLOT_EPS,
988 * GPLOT_LATEX, GPLOT_PNM
989 * \param[in] outroot root of output files
990 * \param[in] title [optional]
991 * \return gplot or null on error
992 *
993 * <pre>
994 * Notes:
995 * (1) This generates plots of each Numa in %naa against %nax,
996 * generated in the specified output format. The title is optional.
997 * (2) Use 0 for default plotstyle (lines).
998 * (3) %nax is optional. If NULL, each Numa array is plotted against
999 * the array index.
1000 * (4) When calling these simple plot functions more than once, use
1001 * different %outroot to avoid overwriting the output files.
1002 * (5) The returned gplot must be destroyed by the caller.
1003 * </pre>
1004 */
1005 GPLOT *
1006 gplotSimpleXYN(NUMA *nax,
1007 NUMAA *naay,
1008 l_int32 plotstyle,
1009 l_int32 outformat,
1010 const char *outroot,
1011 const char *title)
1012 {
1013 l_int32 i, n;
1014 GPLOT *gplot;
1015 NUMA *nay;
1016
1017 if (!naay)
1018 return (GPLOT *)ERROR_PTR("naay not defined", __func__, NULL);
1019 if ((n = numaaGetCount(naay)) == 0)
1020 return (GPLOT *)ERROR_PTR("no numa in array", __func__, NULL);
1021 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
1022 return (GPLOT *)ERROR_PTR("invalid plotstyle", __func__, NULL);
1023 if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
1024 outformat != GPLOT_EPS && outformat != GPLOT_LATEX &&
1025 outformat != GPLOT_PNM)
1026 return (GPLOT *)ERROR_PTR("invalid outformat", __func__, NULL);
1027 if (!outroot)
1028 return (GPLOT *)ERROR_PTR("outroot not specified", __func__, NULL);
1029
1030 if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
1031 return (GPLOT *)ERROR_PTR("gplot not made", __func__, NULL);
1032 for (i = 0; i < n; i++) {
1033 nay = numaaGetNuma(naay, i, L_CLONE);
1034 gplotAddPlot(gplot, nax, nay, plotstyle, NULL);
1035 numaDestroy(&nay);
1036 }
1037 gplotMakeOutput(gplot);
1038 return gplot;
1039 }
1040
1041
1042 /*!
1043 * \brief gplotGeneralPix1()
1044 *
1045 * \param[in] na data array
1046 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
1047 * GPLOT_LINESPOINTS, GPLOT_DOTS
1048 * \param[in] rootname root for all output files
1049 * \param[in] title [optional] overall title
1050 * \param[in] xlabel [optional] x axis label
1051 * \param[in] ylabel [optional] y axis label
1052 * \return pix of plot, or NULL on error
1053 *
1054 * <pre>
1055 * Notes:
1056 * (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
1057 * double quotes and backquotes, but not single quotes.
1058 * </pre>
1059 */
1060 PIX *
1061 gplotGeneralPix1(NUMA *na,
1062 l_int32 plotstyle,
1063 const char *rootname,
1064 const char *title,
1065 const char *xlabel,
1066 const char *ylabel)
1067 {
1068 GPLOT *gplot;
1069 PIX *pix;
1070
1071 if (!na)
1072 return (PIX *)ERROR_PTR("na not defined", __func__, NULL);
1073 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
1074 return (PIX *)ERROR_PTR("invalid plotstyle", __func__, NULL);
1075 if (!rootname)
1076 return (PIX *)ERROR_PTR("rootname not defined", __func__, NULL);
1077
1078 gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel);
1079 if (!gplot)
1080 return (PIX *)ERROR_PTR("gplot not made", __func__, NULL);
1081 gplotAddPlot(gplot, NULL, na, plotstyle, NULL);
1082 pix = gplotMakeOutputPix(gplot);
1083 gplotDestroy(&gplot);
1084 return pix;
1085 }
1086
1087
1088 /*!
1089 * \brief gplotGeneralPix2()
1090 *
1091 * \param[in] na1 x-axis data array
1092 * \param[in] na2 y-axis data array
1093 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
1094 * GPLOT_LINESPOINTS, GPLOT_DOTS
1095 * \param[in] rootname root for all output files
1096 * \param[in] title [optional] overall title
1097 * \param[in] xlabel [optional] x axis label
1098 * \param[in] ylabel [optional] y axis label
1099 * \return pix of plot, or NULL on error
1100 *
1101 * <pre>
1102 * Notes:
1103 * (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
1104 * double quotes and backquotes, but not single quotes.
1105 * </pre>
1106 */
1107 PIX *
1108 gplotGeneralPix2(NUMA *na1,
1109 NUMA *na2,
1110 l_int32 plotstyle,
1111 const char *rootname,
1112 const char *title,
1113 const char *xlabel,
1114 const char *ylabel)
1115 {
1116 GPLOT *gplot;
1117 PIX *pix;
1118
1119 if (!na1)
1120 return (PIX *)ERROR_PTR("na1 not defined", __func__, NULL);
1121 if (!na2)
1122 return (PIX *)ERROR_PTR("na2 not defined", __func__, NULL);
1123 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
1124 return (PIX *)ERROR_PTR("invalid plotstyle", __func__, NULL);
1125 if (!rootname)
1126 return (PIX *)ERROR_PTR("rootname not defined", __func__, NULL);
1127
1128 gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel);
1129 if (!gplot)
1130 return (PIX *)ERROR_PTR("gplot not made", __func__, NULL);
1131 gplotAddPlot(gplot, na1, na2, plotstyle, NULL);
1132 pix = gplotMakeOutputPix(gplot);
1133 gplotDestroy(&gplot);
1134 return pix;
1135 }
1136
1137
1138 /*!
1139 * \brief gplotGeneralPixN()
1140 *
1141 * \param[in] nax x-axis data array
1142 * \param[in] naay array of y-axis data arrays
1143 * \param[in] plotstyle GPLOT_LINES, GPLOT_POINTS, GPLOT_IMPULSES,
1144 * GPLOT_LINESPOINTS, GPLOT_DOTS
1145 * \param[in] rootname root for all output files
1146 * \param[in] title [optional] overall title
1147 * \param[in] xlabel [optional] x axis label
1148 * \param[in] ylabel [optional] y axis label
1149 * \return pix of plot, or NULL on error
1150 *
1151 * <pre>
1152 * Notes:
1153 * (1) The 'title', 'xlabel' and 'ylabel' strings can have spaces,
1154 * double quotes and backquotes, but not single quotes.
1155 * </pre>
1156 */
1157 PIX *
1158 gplotGeneralPixN(NUMA *nax,
1159 NUMAA *naay,
1160 l_int32 plotstyle,
1161 const char *rootname,
1162 const char *title,
1163 const char *xlabel,
1164 const char *ylabel)
1165 {
1166 l_int32 i, n;
1167 GPLOT *gplot;
1168 NUMA *nay;
1169 PIX *pix;
1170
1171 if (!nax)
1172 return (PIX *)ERROR_PTR("nax not defined", __func__, NULL);
1173 if (!naay)
1174 return (PIX *)ERROR_PTR("naay not defined", __func__, NULL);
1175 if ((n = numaaGetCount(naay)) == 0)
1176 return (PIX *)ERROR_PTR("no numa in array", __func__, NULL);
1177 if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
1178 return (PIX *)ERROR_PTR("invalid plotstyle", __func__, NULL);
1179 if (!rootname)
1180 return (PIX *)ERROR_PTR("rootname not defined", __func__, NULL);
1181
1182 gplot = gplotCreate(rootname, GPLOT_PNG, title, xlabel, ylabel);
1183 if (!gplot)
1184 return (PIX *)ERROR_PTR("gplot not made", __func__, NULL);
1185 for (i = 0; i < n; i++) {
1186 nay = numaaGetNuma(naay, i, L_CLONE);
1187 gplotAddPlot(gplot, nax, nay, plotstyle, NULL);
1188 numaDestroy(&nay);
1189 }
1190 pix = gplotMakeOutputPix(gplot);
1191 gplotDestroy(&gplot);
1192 return pix;
1193 }
1194
1195
1196 /*-----------------------------------------------------------------*
1197 * Serialize for I/O *
1198 *-----------------------------------------------------------------*/
1199 /*!
1200 * \brief gplotRead()
1201 *
1202 * \param[in] filename
1203 * \return gplot, or NULL on error
1204 */
1205 GPLOT *
1206 gplotRead(const char *filename)
1207 {
1208 char buf[Bufsize];
1209 char *rootname, *title, *xlabel, *ylabel, *ignores;
1210 l_int32 outformat, ret, version, ignore;
1211 FILE *fp;
1212 GPLOT *gplot;
1213
1214 if (!filename)
1215 return (GPLOT *)ERROR_PTR("filename not defined", __func__, NULL);
1216
1217 if ((fp = fopenReadStream(filename)) == NULL)
1218 return (GPLOT *)ERROR_PTR_1("stream not opened",
1219 filename, __func__, NULL);
1220
1221 ret = fscanf(fp, "Gplot Version %d\n", &version);
1222 if (ret != 1) {
1223 fclose(fp);
1224 return (GPLOT *)ERROR_PTR_1("not a gplot file",
1225 filename, __func__, NULL);
1226 }
1227 if (version != GPLOT_VERSION_NUMBER) {
1228 fclose(fp);
1229 return (GPLOT *)ERROR_PTR_1("invalid gplot version",
1230 filename, __func__, NULL);
1231 }
1232
1233 ignore = fscanf(fp, "Rootname: %511s\n", buf); /* Bufsize - 1 */
1234 rootname = stringNew(buf);
1235 ignore = fscanf(fp, "Output format: %d\n", &outformat);
1236 ignores = fgets(buf, Bufsize, fp); /* Title: ... */
1237 title = stringNew(buf + 7);
1238 title[strlen(title) - 1] = '\0';
1239 ignores = fgets(buf, Bufsize, fp); /* X axis label: ... */
1240 xlabel = stringNew(buf + 14);
1241 xlabel[strlen(xlabel) - 1] = '\0';
1242 ignores = fgets(buf, Bufsize, fp); /* Y axis label: ... */
1243 ylabel = stringNew(buf + 14);
1244 ylabel[strlen(ylabel) - 1] = '\0';
1245
1246 gplot = gplotCreate(rootname, outformat, title, xlabel, ylabel);
1247 LEPT_FREE(rootname);
1248 LEPT_FREE(title);
1249 LEPT_FREE(xlabel);
1250 LEPT_FREE(ylabel);
1251 if (!gplot) {
1252 fclose(fp);
1253 return (GPLOT *)ERROR_PTR_1("gplot not made", filename, __func__, NULL);
1254 }
1255 sarrayDestroy(&gplot->cmddata);
1256 sarrayDestroy(&gplot->datanames);
1257 sarrayDestroy(&gplot->plotdata);
1258 sarrayDestroy(&gplot->plotlabels);
1259 numaDestroy(&gplot->plotstyles);
1260
1261 ignore = fscanf(fp, "Commandfile name: %s\n", buf); /* Bufsize - 1 */
1262 stringReplace(&gplot->cmdname, buf);
1263 ignore = fscanf(fp, "\nCommandfile data:");
1264 gplot->cmddata = sarrayReadStream(fp);
1265 ignore = fscanf(fp, "\nDatafile names:");
1266 gplot->datanames = sarrayReadStream(fp);
1267 ignore = fscanf(fp, "\nPlot data:");
1268 gplot->plotdata = sarrayReadStream(fp);
1269 ignore = fscanf(fp, "\nPlot titles:");
1270 gplot->plotlabels = sarrayReadStream(fp);
1271 ignore = fscanf(fp, "\nPlot styles:");
1272 gplot->plotstyles = numaReadStream(fp);
1273
1274 ignore = fscanf(fp, "Number of plots: %d\n", &gplot->nplots);
1275 ignore = fscanf(fp, "Output file name: %s\n", buf);
1276 stringReplace(&gplot->outname, buf);
1277 ignore = fscanf(fp, "Axis scaling: %d\n", &gplot->scaling);
1278
1279 fclose(fp);
1280 return gplot;
1281 }
1282
1283
1284 /*!
1285 * \brief gplotWrite()
1286 *
1287 * \param[in] filename
1288 * \param[in] gplot
1289 * \return 0 if OK; 1 on error
1290 */
1291 l_ok
1292 gplotWrite(const char *filename,
1293 GPLOT *gplot)
1294 {
1295 FILE *fp;
1296
1297 if (!filename)
1298 return ERROR_INT("filename not defined", __func__, 1);
1299 if (!gplot)
1300 return ERROR_INT("gplot not defined", __func__, 1);
1301
1302 if ((fp = fopenWriteStream(filename, "wb")) == NULL)
1303 return ERROR_INT_1("stream not opened", filename, __func__, 1);
1304
1305 fprintf(fp, "Gplot Version %d\n", GPLOT_VERSION_NUMBER);
1306 fprintf(fp, "Rootname: %s\n", gplot->rootname);
1307 fprintf(fp, "Output format: %d\n", gplot->outformat);
1308 fprintf(fp, "Title: %s\n", gplot->title);
1309 fprintf(fp, "X axis label: %s\n", gplot->xlabel);
1310 fprintf(fp, "Y axis label: %s\n", gplot->ylabel);
1311
1312 fprintf(fp, "Commandfile name: %s\n", gplot->cmdname);
1313 fprintf(fp, "\nCommandfile data:");
1314 sarrayWriteStream(fp, gplot->cmddata);
1315 fprintf(fp, "\nDatafile names:");
1316 sarrayWriteStream(fp, gplot->datanames);
1317 fprintf(fp, "\nPlot data:");
1318 sarrayWriteStream(fp, gplot->plotdata);
1319 fprintf(fp, "\nPlot titles:");
1320 sarrayWriteStream(fp, gplot->plotlabels);
1321 fprintf(fp, "\nPlot styles:");
1322 numaWriteStderr(gplot->plotstyles);
1323
1324 fprintf(fp, "Number of plots: %d\n", gplot->nplots);
1325 fprintf(fp, "Output file name: %s\n", gplot->outname);
1326 fprintf(fp, "Axis scaling: %d\n", gplot->scaling);
1327
1328 fclose(fp);
1329 return 0;
1330 }