You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
507 lines
15 KiB
507 lines
15 KiB
postscript tests fail because of pbmtolps
|
|
backport pbmtolps from netpbm-10.94.3, including tests
|
|
see also bug #670362
|
|
|
|
--- a/converter/pbm/pbmtolps.c
|
|
+++ b/converter/pbm/pbmtolps.c
|
|
@@ -1,181 +1,253 @@
|
|
-/*
|
|
- * pbmtolps -- convert a Portable BitMap into Postscript. The
|
|
- * output Postscript uses lines instead of the image operator to
|
|
- * generate a (device dependent) picture which will be imaged
|
|
- * much faster.
|
|
- *
|
|
- * The Postscript path length is constrained to be less that 1000
|
|
- * points so that no limits are overrun on the Apple Laserwriter
|
|
- * and (presumably) no other printers.
|
|
- *
|
|
- * To do:
|
|
- * make sure encapsulated format is correct
|
|
- * repitition of black-white strips
|
|
- * make it more device independent (is this possible?)
|
|
- *
|
|
- * Author:
|
|
- * George Phillips <phillips@cs.ubc.ca>
|
|
- * Department of Computer Science
|
|
- * University of British Columbia
|
|
- */
|
|
-
|
|
-#include <string.h>
|
|
-#include <stdio.h>
|
|
+/*=============================================================================
|
|
+ pbmtolps
|
|
+===============================================================================
|
|
+
|
|
+ Convert a PBM image to Postscript. The output Postscript uses lines instead
|
|
+ of the image operator to generate a (device dependent) picture which will be
|
|
+ imaged much faster.
|
|
+
|
|
+ The Postscript path length is constrained to be at most 1000 vertices so that
|
|
+ no limits are overrun on the Apple Laserwriter and (presumably) no other
|
|
+ printers. The typical limit is 1500. See "4.4 Path Construction" and
|
|
+ "Appendix B: Implementation Limits" in: PostScript Language Reference Manual
|
|
+ https://www.adobe.com/content/dam/acom/en/devnet/actionscript/
|
|
+ articles/psrefman.pdf
|
|
+
|
|
+ To do:
|
|
+ make sure encapsulated format is correct
|
|
+ repetition of black-white strips
|
|
+ make it more device independent (is this possible?)
|
|
+
|
|
+ Author:
|
|
+ George Phillips <phillips@cs.ubc.ca>
|
|
+ Department of Computer Science
|
|
+ University of British Columbia
|
|
+=============================================================================*/
|
|
+#include <stdbool.h>
|
|
|
|
+#include "pm_c_util.h"
|
|
+#include "mallocvar.h"
|
|
#include "nstring.h"
|
|
+#include "shhopt.h"
|
|
#include "pbm.h"
|
|
|
|
|
|
-static int prev_white = -1;
|
|
-static int prev_black = -1;
|
|
-static char cmd = '\0';
|
|
-static int pointcount = 2;
|
|
-
|
|
-#ifdef RUN
|
|
-static int run = 1;
|
|
-#endif
|
|
-
|
|
-static char
|
|
-morepoints(char cmd, int howmany_pbmtolps) {
|
|
- pointcount += 2;
|
|
- if (pointcount > 1000) {
|
|
- pointcount = 2;
|
|
- cmd += 'm' - 'a';
|
|
- }
|
|
- return(cmd);
|
|
+static float const MAX_DPI = 5000;
|
|
+static float const MIN_DPI = 10;
|
|
+static unsigned int const MAX_PATH_VERTICES = 1000;
|
|
+
|
|
+
|
|
+struct CmdlineInfo {
|
|
+ /* All the information the user supplied in the command line, in a form
|
|
+ easy for the program to use.
|
|
+ */
|
|
+ const char * inputFileName; /* File name of input file */
|
|
+ unsigned int inputFileSpec; /* Input file name specified */
|
|
+ float lineWidth; /* Line width, if specified */
|
|
+ unsigned int lineWidthSpec; /* Line width specified */
|
|
+ float dpi; /* Resolution in DPI, if specified */
|
|
+ unsigned int dpiSpec; /* Resolution specified */
|
|
+};
|
|
+
|
|
+
|
|
+
|
|
+static void
|
|
+validateDpi(float const dpi) {
|
|
+
|
|
+ if (dpi > MAX_DPI || dpi < MIN_DPI)
|
|
+ pm_error("Specified DPI value out of range (%f)", dpi);
|
|
}
|
|
|
|
|
|
|
|
-static void
|
|
-addstrip(int const white,
|
|
- int const black) {
|
|
-
|
|
- if (cmd) {
|
|
-#ifdef RUN
|
|
- if (white == prev_white && black == prev_black)
|
|
- run++;
|
|
- else {
|
|
- if (run == 1)
|
|
-#endif
|
|
- printf("%d %d %c ",
|
|
- prev_black, prev_white, morepoints(cmd, 2));
|
|
-#ifdef RUN
|
|
- else
|
|
- /* of course, we need to give a new command */
|
|
- printf("%d %d %d %c ",
|
|
- prev_white, prev_black, run,
|
|
- morepoints(cmd + 'f' - 'a', 2 * run));
|
|
- run = 1;
|
|
- }
|
|
-#endif
|
|
+static void
|
|
+parseCommandLine(int argc,
|
|
+ const char ** const argv,
|
|
+ struct CmdlineInfo * const cmdlineP) {
|
|
+/*----------------------------------------------------------------------------
|
|
+ Parse program command line described in Unix standard form by argc
|
|
+ and argv. Return the information in the options as *cmdlineP.
|
|
+-----------------------------------------------------------------------------*/
|
|
+ optEntry * option_def; /* malloc'ed */
|
|
+ /* Instructions to OptParseOptions3 on how to parse our options. */
|
|
+ optStruct3 opt;
|
|
+
|
|
+ unsigned int option_def_index;
|
|
+
|
|
+ MALLOCARRAY_NOFAIL(option_def, 100);
|
|
+
|
|
+ option_def_index = 0; /* incremented by OPTENTRY */
|
|
+ OPTENT3(0, "linewidth", OPT_FLOAT, &cmdlineP->lineWidth,
|
|
+ &cmdlineP->lineWidthSpec, 0);
|
|
+ OPTENT3(0, "dpi", OPT_FLOAT, &cmdlineP->dpi,
|
|
+ &cmdlineP->dpiSpec, 0);
|
|
+
|
|
+ opt.opt_table = option_def;
|
|
+ opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
|
|
+ opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
|
|
+
|
|
+ pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
|
|
+ /* Uses and sets argc, argv, and some of *cmdlineP and others. */
|
|
+
|
|
+ if (cmdlineP->dpiSpec)
|
|
+ validateDpi(cmdlineP->dpi);
|
|
+ else
|
|
+ cmdlineP->dpi = 300;
|
|
+
|
|
+ if (argc-1 < 1)
|
|
+ cmdlineP->inputFileName = "-";
|
|
+ else {
|
|
+ if (argc-1 > 1)
|
|
+ pm_error("Program takes zero or one argument (filename). You "
|
|
+ "specified %u", argc-1);
|
|
+ else
|
|
+ cmdlineP->inputFileName = argv[1];
|
|
}
|
|
|
|
- prev_white = white;
|
|
- prev_black = black;
|
|
- cmd = 'a';
|
|
+ if (cmdlineP->inputFileName[0] == '-' &&
|
|
+ cmdlineP->inputFileName[1] == '\0')
|
|
+ cmdlineP->inputFileSpec = false;
|
|
+ else
|
|
+ cmdlineP->inputFileSpec = true;
|
|
+
|
|
+ free(option_def);
|
|
}
|
|
|
|
|
|
|
|
-static void
|
|
-nextline(void) {
|
|
- /* need to check run, should have an outcommand */
|
|
- if (cmd)
|
|
- printf("%d %d %c\n", prev_black, prev_white, morepoints('c', 3));
|
|
- else
|
|
- printf("%c\n", morepoints('b', 1));
|
|
- cmd = '\0';
|
|
+static void
|
|
+validateLineWidth(float const scCols,
|
|
+ float const scRows,
|
|
+ float const lineWidth) {
|
|
+
|
|
+ if (lineWidth >= scCols || lineWidth >= scRows)
|
|
+ pm_error("Absurdly large -linewidth value (%f)", lineWidth);
|
|
}
|
|
|
|
|
|
|
|
-int
|
|
-main(int argc, char ** argv) {
|
|
- FILE* fp;
|
|
- bit* bits;
|
|
- int row;
|
|
- int col;
|
|
- int rows;
|
|
- int cols;
|
|
- int format;
|
|
- int white;
|
|
- int black;
|
|
- const char* name;
|
|
- float dpi = 300.0;
|
|
- float sc_rows;
|
|
- float sc_cols;
|
|
- int i;
|
|
- const char* const usage = "[ -dpi n ] [ pbmfile ]";
|
|
-
|
|
-
|
|
- pbm_init(&argc, argv);
|
|
-
|
|
- i = 1;
|
|
- if (i < argc && streq(argv[i], "-dpi")) {
|
|
- if (i == argc - 1)
|
|
- pm_usage(usage);
|
|
- sscanf(argv[i + 1], "%f", &dpi);
|
|
- i += 2;
|
|
- }
|
|
+static void
|
|
+doRaster(FILE * const ifP,
|
|
+ unsigned int const cols,
|
|
+ unsigned int const rows,
|
|
+ int const format,
|
|
+ FILE * const ofP) {
|
|
|
|
- if (i < argc - 1)
|
|
- pm_usage(usage);
|
|
+ bit * bitrow;
|
|
+ unsigned int row;
|
|
+ unsigned int vertexCt;
|
|
+ /* Number of vertices drawn since last stroke command */
|
|
|
|
- if (i == argc) {
|
|
- name = "noname";
|
|
- fp = stdin;
|
|
- } else {
|
|
- name = argv[i];
|
|
- fp = pm_openr(name);
|
|
- }
|
|
- pbm_readpbminit(fp, &cols, &rows, &format);
|
|
- bits = pbm_allocrow(cols);
|
|
+ bitrow = pbm_allocrow(cols);
|
|
+
|
|
+ for (row = 0, vertexCt = 0; row < rows; ++row) {
|
|
+ unsigned int col;
|
|
+ bool firstRun;
|
|
|
|
- sc_rows = (float)rows / dpi * 72.0;
|
|
- sc_cols = (float)cols / dpi * 72.0;
|
|
+ firstRun = true; /* initial value */
|
|
+
|
|
+ pbm_readpbmrow(ifP, bitrow, cols, format);
|
|
+
|
|
+ /* output white-strip + black-strip sequences */
|
|
|
|
- puts("%!PS-Adobe-2.0 EPSF-2.0");
|
|
- puts("%%Creator: pbmtolps");
|
|
- printf("%%%%Title: %s\n", name);
|
|
- printf("%%%%BoundingBox: %d %d %d %d\n",
|
|
- (int)(305.5 - sc_cols / 2.0),
|
|
- (int)(395.5 - sc_rows / 2.0),
|
|
- (int)(306.5 + sc_cols / 2.0),
|
|
- (int)(396.5 + sc_rows / 2.0));
|
|
- puts("%%EndComments");
|
|
- puts("%%EndProlog");
|
|
- puts("gsave");
|
|
-
|
|
- printf("%f %f translate\n", 306.0 - sc_cols / 2.0, 396.0 + sc_rows / 2.0);
|
|
- printf("72 %f div dup neg scale\n", dpi);
|
|
- puts("/a { 0 rmoveto 0 rlineto } def");
|
|
- puts("/b { 0 row 1 add dup /row exch def moveto } def");
|
|
- puts("/c { a b } def");
|
|
- puts("/m { currentpoint stroke newpath moveto a } def");
|
|
- puts("/n { currentpoint stroke newpath moveto b } def");
|
|
- puts("/o { currentpoint stroke newpath moveto c } def");
|
|
- puts("/row 0 def");
|
|
- puts("newpath 0 0 moveto");
|
|
-
|
|
- for (row = 0; row < rows; row++) {
|
|
- pbm_readpbmrow(fp, bits, cols, format);
|
|
- /* output white-strip+black-strip sequences */
|
|
for (col = 0; col < cols; ) {
|
|
- for (white = 0; col < cols && bits[col] == PBM_WHITE; col++)
|
|
- white++;
|
|
- for (black = 0; col < cols && bits[col] == PBM_BLACK; col++)
|
|
- black++;
|
|
+ unsigned int whiteCt;
|
|
+ unsigned int blackCt;
|
|
+
|
|
+ for (whiteCt = 0; col < cols && bitrow[col] == PBM_WHITE; ++col)
|
|
+ ++whiteCt;
|
|
+ for (blackCt = 0; col < cols && bitrow[col] == PBM_BLACK; ++col)
|
|
+ ++blackCt;
|
|
+
|
|
+ if (blackCt > 0) {
|
|
+ if (vertexCt > MAX_PATH_VERTICES) {
|
|
+ printf("m ");
|
|
+ vertexCt = 0;
|
|
+ }
|
|
+
|
|
+ if (firstRun) {
|
|
+ printf("%u %u moveto %u 0 rlineto\n",
|
|
+ whiteCt, row, blackCt);
|
|
+ firstRun = false;
|
|
+ } else
|
|
+ printf("%u %u a\n", blackCt, whiteCt);
|
|
|
|
- if (black != 0)
|
|
- addstrip(white, black);
|
|
+ vertexCt += 2;
|
|
+ }
|
|
}
|
|
- nextline();
|
|
}
|
|
- puts("stroke grestore showpage");
|
|
- puts("%%Trailer");
|
|
+ pbm_freerow(bitrow);
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+static void
|
|
+pbmtolps(FILE * const ifP,
|
|
+ FILE * const ofP,
|
|
+ struct CmdlineInfo const cmdline) {
|
|
+
|
|
+ const char * const psName =
|
|
+ cmdline.inputFileSpec ? cmdline.inputFileName : "noname";
|
|
+
|
|
+ int rows;
|
|
+ int cols;
|
|
+ int format;
|
|
+ float scRows, scCols;
|
|
+ /* Dimensions of the printed image in points */
|
|
+
|
|
+ pbm_readpbminit(ifP, &cols, &rows, &format);
|
|
+
|
|
+ scRows = (float) rows / (cmdline.dpi / 72.0);
|
|
+ scCols = (float) cols / (cmdline.dpi / 72.0);
|
|
+
|
|
+ if (cmdline.lineWidthSpec)
|
|
+ validateLineWidth(scCols, scRows, cmdline.lineWidth);
|
|
+
|
|
+ fputs("%!PS-Adobe-2.0 EPSF-2.0\n", ofP);
|
|
+ fputs("%%Creator: pbmtolps\n", ofP);
|
|
+ fprintf(ofP, "%%%%Title: %s\n", psName);
|
|
+ fprintf(ofP, "%%%%BoundingBox: %d %d %d %d\n",
|
|
+ (int)(305.5 - scCols / 2.0),
|
|
+ (int)(395.5 - scRows / 2.0),
|
|
+ (int)(306.5 + scCols / 2.0),
|
|
+ (int)(396.5 + scRows / 2.0));
|
|
+ fputs("%%EndComments\n", ofP);
|
|
+ fputs("%%EndProlog\n", ofP);
|
|
+ fputs("gsave\n", ofP);
|
|
+
|
|
+ fprintf(ofP, "%f %f translate\n",
|
|
+ 306.0 - scCols / 2.0, 396.0 + scRows / 2.0);
|
|
+ fprintf(ofP, "72 %f div dup neg scale\n", cmdline.dpi);
|
|
+
|
|
+ if (cmdline.lineWidthSpec)
|
|
+ fprintf(ofP, "%f setlinewidth\n", cmdline.lineWidth);
|
|
+
|
|
+ fputs("/a { 0 rmoveto 0 rlineto } def\n", ofP);
|
|
+ fputs("/m { currentpoint stroke newpath moveto } def\n", ofP);
|
|
+ fputs("newpath 0 0 moveto\n", ofP);
|
|
+
|
|
+ doRaster(ifP, cols, rows, format, ofP);
|
|
+
|
|
+ fputs("stroke grestore showpage\n", ofP);
|
|
+ fputs("%%Trailer\n", ofP);
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+int
|
|
+main(int argc, const char *argv[]) {
|
|
+ FILE * ifP;
|
|
+ struct CmdlineInfo cmdline;
|
|
+
|
|
+ pm_proginit(&argc, argv);
|
|
+
|
|
+ parseCommandLine(argc, argv, &cmdline);
|
|
+
|
|
+ ifP = pm_openr(cmdline.inputFileName);
|
|
+
|
|
+ pbmtolps(ifP, stdout, cmdline);
|
|
|
|
- pm_close(fp);
|
|
+ pm_close(ifP);
|
|
|
|
- exit(0);
|
|
+ return 0;
|
|
}
|
|
--- a/test/lps-roundtrip.ok
|
|
+++ b/test/lps-roundtrip.ok
|
|
@@ -0,0 +1 @@
|
|
+match
|
|
--- a/test/lps-roundtrip.test
|
|
+++ b/test/lps-roundtrip.test
|
|
@@ -0,0 +1,22 @@
|
|
+#! /bin/bash
|
|
+# This script tests: pbmtolps pstopnm
|
|
+# Also requires: gs pamdepth pamscale pnmcrop pnmpsnr
|
|
+
|
|
+# The ordinary round-trip does not work because of the way ghostscript
|
|
+# renders: a line is considered wider than a single pixel and all pixels
|
|
+# it touches are set to black if the output is PBM. To work around this,
|
|
+# we tell pstopnm to output PGM at a high resolution (=large dpi value).
|
|
+
|
|
+
|
|
+test_pgm=${tmpdir}/testgrid.pgm
|
|
+
|
|
+pamdepth 255 testgrid.pbm > ${test_pgm}
|
|
+
|
|
+pbmtolps -dpi 72 testgrid.pbm | \
|
|
+ pstopnm -dpi $((72*12)) -stdout -pgm | \
|
|
+ pnmcrop -white | pamscale -xsize=14 -ysize=16 | \
|
|
+ pnmpsnr -target=30 - ${test_pgm}
|
|
+
|
|
+# ghostscript version 8.71: pnmpsnr lumina 33.14dB
|
|
+
|
|
+rm ${test_pgm}
|
|
--- a/test/ps-alt-roundtrip.ok
|
|
+++ b/test/ps-alt-roundtrip.ok
|
|
@@ -1,3 +1,2 @@
|
|
2425386270 41
|
|
-2425386270 41
|
|
2916080186 235
|
|
--- a/test/ps-alt-roundtrip.test
|
|
+++ b/test/ps-alt-roundtrip.test
|
|
@@ -1,21 +1,24 @@
|
|
#! /bin/bash
|
|
-# This script tests: pbmtoepsi pbmtopsg3 pbmtolps psidtopgm pstopnm
|
|
+# This script tests: pbmtoepsi pbmtopsg3 psidtopgm pstopnm
|
|
# Also requires: gs pnmcrop
|
|
|
|
|
|
# This script is for testing alternative (or minor) utilities that
|
|
# read/write Postscript and encapsulated Postscript:
|
|
-# pbmtoepsi, pbmtopsg3, pbmtolps and psidtopgm.
|
|
+# pbmtoepsi, pbmtopsg3 and psidtopgm.
|
|
#
|
|
# We keep these tests separate from those for pnmtops and pstopnm
|
|
# which are far more popular.
|
|
#
|
|
-# pbmtopsg3 and pbmtolps produce output that require pstopnm for decoding.
|
|
+# pbmtopsg3 produces output that requires pstopnm for decoding.
|
|
+#
|
|
+# We used to test pbmtolps here, but moved it out when gs changed its
|
|
+# rendering formula.
|
|
#
|
|
# Failure message
|
|
## If ps-roundtrip.test succeeds and this test fails, it is most likely
|
|
## a problem with one of the alternate Postscipt utilities:
|
|
-## pbmtoepsi, pbmtopsg3, pbmtolps or psidtopgm.
|
|
+## pbmtoepsi, pbmtopsg3, or psidtopgm.
|
|
## If both tests fail it indicates a problem with pstopnm or gs.
|
|
|
|
# pstopnm does not use libnetpbm functions for output.
|
|
@@ -33,18 +36,8 @@
|
|
rm ${testgrid1_ps}
|
|
|
|
|
|
-# Test 2. Should print: 2425386270 41
|
|
-testgrid2_ps=${tmpdir}/testgrid2.ps
|
|
-
|
|
-pbmtolps -dpi 72 testgrid.pbm \
|
|
- > ${testgrid2_ps} && \
|
|
-pstopnm -xborder=0 -yborder=0 -dpi=72 -stdout \
|
|
- -quiet ${testgrid2_ps} -pbm | \
|
|
- pnmcrop | cksum
|
|
-
|
|
-rm ${testgrid2_ps}
|
|
|
|
-# Test 3. Should print: 2916080186 235
|
|
+# Test 2. Should print: 2916080186 235
|
|
# Output is pgm maxval=1 with black and white inverted.
|
|
#
|
|
testgrid_epsi=${tmpdir}/testgrid.epsi
|
|
--- a/test/Test-Order
|
|
+++ b/test/Test-Order
|
|
@@ -183,5 +183,6 @@
|
|
|
|
fiasco-roundtrip.test
|
|
jpeg-roundtrip.test
|
|
+lps-roundtrip.test
|
|
tiffcmyk-roundtrip.test
|
|
yuv-roundtrip.test
|