diff options
40 files changed, 1091 insertions, 472 deletions
diff --git a/GNUmakefile b/GNUmakefile index c6077285..035a8ed5 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -60,7 +60,7 @@ VPATH=.:$(SRCDIR) include $(BUILDDIR)/config.mk -PROG_SUBDIRS = converter analyzer editor generator other +PROG_SUBDIRS = converter analyzer editor generator other test PRODUCT_SUBDIRS = lib $(PROG_SUBDIRS) SUPPORT_SUBDIRS = urt buildtools @@ -161,6 +161,11 @@ ifeq ($(HAVE_INT64),Y) else echo "#define HAVE_INT64 0" >>$@ endif +ifeq ($(WANT_SSE),Y) + echo "#define WANT_SSE 1" >>$@ +else + echo "#define WANT_SSE 0" >>$@ +endif ifeq ($(DONT_HAVE_PROCESS_MGMT),Y) echo "#define HAVE_FORK 0" >>$@ else diff --git a/buildtools/Makefile b/buildtools/Makefile index e90feeca..6a2e33da 100644 --- a/buildtools/Makefile +++ b/buildtools/Makefile @@ -8,24 +8,10 @@ include $(BUILDDIR)/config.mk MERGE_OBJECTS = -# These are programs that are used by the make files: -BUILDPROGS = libopt typegen endiangen - -# Ideally, this directory would not contain anything but build tools, which -# means they would all be built to run in the build environment, not the -# target environment. But we have no other convenient place for test tools, -# so we put them here and build them for the target environment. -TESTPROGS = testrandom - -PROGS = $(BUILDPROGS) $(TESTPROGS) +PROGS = libopt typegen endiangen all: $(PROGS) -PORTBINARIES = $(TESTPROGS) -BINARIES = $(PORTBINARIES) -OBJECTS = $(BINARIES:%=%.o) -SCRIPTS = - OMIT_BUILDTOOL_RULE = 1 include $(SRCDIR)/common.mk @@ -40,7 +26,8 @@ endif libopt.o: libopt.c $(CC_FOR_BUILD) -c -o $@ $(CFLAGS_FOR_BUILD) \ -DSHLIBPREFIXLIST="\"$(SHLIBPREFIXLIST)\"" \ - $(STRIP_DLL_VERSION) $(EXPLICIT) $(CFLAGS_PERSONAL) $(CADD) \ + $(STRIP_DLL_VERSION) $(EXPLICIT) \ + $(CFLAGS_PERSONAL) $(CFLAGS) $(CADD) \ $< typegen.o endiangen.o:%.o:%.c diff --git a/buildtools/configure.pl b/buildtools/configure.pl index 2179454b..b03630d8 100755 --- a/buildtools/configure.pl +++ b/buildtools/configure.pl @@ -99,7 +99,7 @@ sub prompt($$) { sub promptYesNo($) { - my ($default) = $@; + my ($default) = @_; my $retval; @@ -947,6 +947,7 @@ sub getInttypes($) { } + sub getInt64($$) { my ($inttypes_h, $haveInt64R) = @_; @@ -982,6 +983,72 @@ sub getInt64($$) { +sub determineSseCapability($) { + + my ($haveEmmintrinR) = @_; + + if (defined($testCc)) { + + print("(Doing test compiles to determine if your compiler has SSE " . + "intrinsics -- ignore errors)\n"); + + my $cflags = testCflags(); + + my $works; + + my @cSourceCode = ( + "#include <emmintrin.h>\n", + ); + + testCompile($cflags, \@cSourceCode, \my $success); + + if ($success) { + print("It does.\n"); + $$haveEmmintrinR = $TRUE; + } else { + print("It does not. Programs will not exploit fast SSE " . + "instructions.\n"); + $$haveEmmintrinR = $FALSE; + } + print("\n"); + } else { + # We conservatively estimate the facility isn't there + $$haveEmmintrinR = $FALSE; + } +} + + + +sub getSse($) { + + my ($wantSseR) = @_; + + determineSseCapability(\my $haveEmmintrin); + + my $gotit; + + print("Use SSE instructions?\n"); + print("\n"); + + my $default = $haveEmmintrin ? "y" : "n"; + + $$wantSseR = promptYesNo($default); + + # Another complication in the SSE world is that GNU compiler options + # -msse, -msse2, and -march=xxx affect whether the compiler can or will + # generate the instructions. When compiling for older processors, the + # default for these options is negative ; for newer processors, it is + # affirmative. -[no]msse2 determines whether macro __SSE2__ macro is + # defined. If it is not, #include <emmintrins.h> fails (<emmintrins.h> + # checks __SSE2__. + + # The Netpbm build does not mess with these compiler options. If the + # user wants something other than the default, he can put it in CFLAGS + # in config.mk manually or on the make command line on in CFLAGS_PERSONAL. +} + + + # TODO: These should do test compiles to see if the headers are in the # default search path, both to create a default to offer and to issue a # warning after user has chosen. Also test links to test the link library. @@ -1959,6 +2026,8 @@ getInttypes(\my $inttypesHeaderFile); getInt64($inttypesHeaderFile, \my $haveInt64); +getSse(\my $wantSse); + findProcessManagement(\my $dontHaveProcessMgmt); #****************************************************************************** @@ -2385,6 +2454,10 @@ if ($haveInt64 ne 'Y') { push(@config_mk, "HAVE_INT64 = $haveInt64\n"); } +if ($wantSse) { + push(@config_mk, "WANT_SSE = Y\n"); +} + if ($dontHaveProcessMgmt) { push(@config_mk, "DONT_HAVE_PROCESS_MGMT = Y\n"); } diff --git a/common.mk b/common.mk index 4077f2ea..c096bd6e 100644 --- a/common.mk +++ b/common.mk @@ -43,13 +43,11 @@ # MERGEBINARIES: list of the programs that, in a merge build, are invoked # via the merged Netpbm program # CC: C compiler command -# CPPFLAGS: C preprocessor options -# CFLAGS: C compiler general options +# CFLAGS_CONFIG: C compiler options from config.mk. # CFLAGS_TARGET: C compiler options for a particular target # LD: linker command # LINKERISCOMPILER: 'Y' if the linker invoked by LD is actually a compiler # front end, so takes linker options in a different format -# LDFLAGS: linker options # LIBS or LOADLIBES: names of libraries to be added to all links # COMP_INCLUDES: Compiler option string to establish the search path for # component-specific include files when compiling things or computing @@ -64,6 +62,10 @@ # is intended to be set on a make command line (e.g. 'make CADD=-g') # for options that apply just to a particular build. +# In addition, there is CFLAGS, which is extra C compilation options and is +# expected to be set via the make command line for a particular build. +# Likewise, LDFLAGS for link-edit options. + # In addition, there is CFLAGS_PERSONAL, which is extra C # compilation options and is expected to be set via environment variable # for options that are particular to the person doing the build and not @@ -235,7 +237,19 @@ config: # -UNDEBUG (in any of various ways) to override this. # CFLAGS_ALL = \ - -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_TARGET) $(CFLAGS_PERSONAL) $(CADD) + -DNDEBUG $(CPPFLAGS) $(CFLAGS_CONFIG) $(CFLAGS_TARGET) $(CFLAGS_PERSONAL) $(CFLAGS) $(CADD) + +ifeq ($(WANT_SSE),Y) + # The only two compilers we've seen that have the SSE capabilities that + # WANT_SSE requests are GCC and Clang, and they both have these options and + # require them in order for <emmintrin.h> to compile. On some systems + # (x86_64, in our experience), these options are default, but on more + # traditional systems, they are not. Note: __SSE2__ macro tells whether + # -msse2 is in effect. + CFLAGS_SSE = -msse -msse2 +else + CFLAGS_SSE = +endif $(OBJECTS): %.o: %.c importinc ############################################################################# diff --git a/config.mk.in b/config.mk.in index 3873ba19..bc1d2804 100644 --- a/config.mk.in +++ b/config.mk.in @@ -89,6 +89,17 @@ INTTYPES_H = <inttypes.h> HAVE_INT64 = Y #HAVE_INT64 = N +# WANT_SSE tells whether the build should use SSE instructions, via the the +# standard SSE intrinsics (operators such as '_mm_movemask_epi8'). SSE +# instructions are faster than traditional instructions, but aren't available +# on all CPUs. Also, the standard intrinsics are not available in all +# compilers. Even if you say N here, Netpbm may still be built with some +# SSE exploitation (e.g. SSE floating point) because the compiler will +# do it automatically. You can add a -nomsse or -nomsse2 option to +# CFLAGS or CFLAGS_PERSONAL to stop that. +WANT_SSE = N +#WANT_SSE = Y + # CC and LD are for building the Netpbm programs, which are not necessarily # intended to run on the same system on which Make is running. But when we # build a build tool such as Libopt, it is meant to run only on the same @@ -96,7 +107,7 @@ HAVE_INT64 = Y # to use to compile and link build tools. CC_FOR_BUILD = $(CC) LD_FOR_BUILD = $(LD) -CFLAGS_FOR_BUILD = $(CFLAGS) +CFLAGS_FOR_BUILD = $(CFLAGS_CONFIG) LDFLAGS_FOR_BUILD = $(LDFLAGS) # MAKE is set automatically by Make to what was used to invoke Make. diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile index 20a95aa2..4470d472 100644 --- a/converter/other/cameratopam/Makefile +++ b/converter/other/cameratopam/Makefile @@ -9,7 +9,7 @@ EXTERN_INCLUDES = ifneq ($(JPEGLIB),NONE) ifneq ($(JPEGHDR_DIR)x,x) EXTERN_INCLUDES += -I$(JPEGHDR_DIR) - CFLAGS += -DHAVE_JPEG + HAVE_JPEG_DEFINE = -DHAVE_JPEG endif endif @@ -22,6 +22,8 @@ all: cameratopam OBJECTS = util.o identify.o cameratopam.o camera.o foveon.o decode.o \ canon.o ljpeg.o dng.o +camera.o camera.o2: CFLAGS_TARGET = $(HAVE_JPEG_DEFINE) + MERGE_OBJECTS = BINARIES = cameratopam diff --git a/converter/other/jpeg2000/libjasper/common.mk b/converter/other/jpeg2000/libjasper/common.mk index b31b1209..a333f5d6 100644 --- a/converter/other/jpeg2000/libjasper/common.mk +++ b/converter/other/jpeg2000/libjasper/common.mk @@ -13,8 +13,7 @@ partlist: $(SUBDIRS:%=%/partlist) cat /dev/null $(SUBDIRS:%=%/partlist) >$@ echo $(LIB_OBJECTS:%=$(CURDIR)/%) >>$@ -.PHONY: $(SUBDIRS:%=%/partlist) -$(SUBDIRS:%=%/partlist): %/partlist: $(CURDIR)/% +$(SUBDIRS:%=%/partlist): $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile index 7f99f95a..65790002 100644 --- a/converter/other/pnmtopalm/Makefile +++ b/converter/other/pnmtopalm/Makefile @@ -25,7 +25,7 @@ $(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) gen_palm_colormap : % : %.c palmcolormap.o - $(CC) -I importinc $(CPPFLAGS) $(CFLAGS) -o $@ \ + $(CC) -I importinc $(CFLAGS_ALL) -o $@ \ $< palmcolormap.o \ $(LIBOPTS) $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(LADD) diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c index 150331a1..316b7626 100644 --- a/converter/other/pnmtops.c +++ b/converter/other/pnmtops.c @@ -114,8 +114,10 @@ struct cmdlineInfo { unsigned int dict; unsigned int vmreclaim; unsigned int verbose; + unsigned int debug; }; +static bool debug; static bool verbose; @@ -248,6 +250,7 @@ parseCommandLine(int argc, const char ** argv, OPTENT3(0, "vmreclaim", OPT_FLAG, NULL, &cmdlineP->vmreclaim, 0); OPTENT3(0, "showpage", OPT_FLAG, NULL, &showpage, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "debug", OPT_FLAG, NULL, &cmdlineP->debug, 0); OPTENT3(0, "level", OPT_UINT, &cmdlineP->level, &cmdlineP->levelSpec, 0); @@ -395,6 +398,16 @@ writeFileChar(const char * const buffer, +static void +writeFileByte(unsigned char const byte, + const char * const name, + FILE * const ofP) { + + writeFile(&byte, 1, name, ofP); +} + + + #define MAX_FILTER_CT 10 /* The maximum number of filters this code is capable of applying */ @@ -621,17 +634,28 @@ flateFilter(FILE * const ifP, static void -rlePutBuffer (unsigned int const repeat, +rlePutBuffer (bool const repeatMode, unsigned int const count, - unsigned int const repeatitem, + unsigned char const repeatitem, unsigned char * const itembuf, FILE * const fP) { +/*---------------------------------------------------------------------------- + Output some RLE data. There are two forms of output: - if (repeat) { - fputc(257 - count, fP); - fputc(repeatitem, fP); + 'repeatMode' true: output a repeat sequence, indicating to repeat byte + 'repeatitem' 'count' times. + + 'repeatMode' false: output a non-repeat sequence indicating the + 'count' characters in itembuf[]. +-----------------------------------------------------------------------------*/ + assert(count > 0); + assert(count <= 128); + + if (repeatMode) { + writeFileByte((257 - count) % 256, "rlePutBuffer", fP); + writeFileByte(repeatitem, "rlePutBuffer", fP); } else { - fputc(count - 1, fP); + writeFileByte(count - 1, "rlePutBuffer", fP); writeFile(itembuf, count, "rlePutBuffer", fP); } } @@ -975,6 +999,12 @@ addFilter(const char * const description, pm_message("%s filter spawned: pid %u", description, (unsigned)pid); + if (debug) { + int const outFd = fileno(oldFeedFileP); + int const supplyFd = fileno(newFeedFileP); + pm_message("PID %u writes to FD %u, its supplier writes to FD %u", + (unsigned)pid, outFd, supplyFd); + } fclose(oldFeedFileP); /* Child keeps this open now */ addToPidList(pidList, pid); @@ -1937,7 +1967,17 @@ convertRaster(struct pam * const inpamP, unsigned int const bitsPerSample, bool const psFilter, FILE * const fP) { +/*---------------------------------------------------------------------------- + Read the raster described by *inpamP, and write a bit stream of samples + to *fP. This stream has to be compressed and converted to text before it + can be part of a Postscript program. + + 'psFilter' means to do the conversion using built in Postscript filters, as + opposed to our own filters via /readstring. + 'bitsPerSample' is how many bits each sample is to take in the Postscript + output. +-----------------------------------------------------------------------------*/ if (PAM_FORMAT_TYPE(inpamP->format) == PBM_TYPE && bitsPerSample == 1) { unsigned char * bitrow; unsigned int row; @@ -2097,7 +2137,8 @@ main(int argc, const char * argv[]) { parseCommandLine(argc, argv, &cmdline); - verbose = cmdline.verbose; + verbose = cmdline.verbose || cmdline.debug; + debug = cmdline.debug; if (cmdline.flate && !progIsFlateCapable()) pm_error("This program cannot do flate compression. " diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c index f4081464..c0d6a4ee 100644 --- a/converter/other/pstopnm.c +++ b/converter/other/pstopnm.c @@ -496,42 +496,72 @@ computeBoxToExtract(struct Box const cmdlineExtractBox, static enum Orientation computeOrientation(struct CmdlineInfo const cmdline, struct Box const extractBox) { - - unsigned int const inputWidth = extractBox.urx - extractBox.llx; - unsigned int const inputHeight = extractBox.ury - extractBox.lly; +/*---------------------------------------------------------------------------- + The proper orientation of the image on the page, given the user's + parameters 'cmdline' and the image dimensions 'extractBox'. +-----------------------------------------------------------------------------*/ + /* We're putting an _image_ on a _page_. Either one can have portrait or + landscape aspect ratio. In our return value, orientation just means + whether the image is rotated on the page: Portrait means it isn't + Landscape means it is. The result can be confusing: Consider an image + which is a landscape, wider than it is tall, being printed on a page + which is also wider than it is tall. The orientation we would return + for that case is Portrait. + + The decision is simple: if the user didn't request a particular + orientation, we return the value that makes the image orientation match + the page orientation. If both possibilities match equally (because the + image or the page is square), we return Portrait. + */ enum Orientation retval; if (cmdline.orientation != UNSPECIFIED) retval = cmdline.orientation; else { - if ((!cmdline.xsize || !cmdline.ysize) & - (cmdline.xsize || cmdline.ysize)) { - /* User specified one output dimension, but not the other, - so we can't use output dimensions to make the decision. So - just use the input dimensions. - */ - if (inputHeight > inputWidth) retval = PORTRAIT; - else retval = LANDSCAPE; + /* Dimensions of image to print, in points */ + unsigned int const imageWidPt = extractBox.urx - extractBox.llx; + unsigned int const imageHgtPt = extractBox.ury - extractBox.lly; + + /* Dimensions of image to print, in pixels (possibly of assumed + resolution) + */ + unsigned int imageWidXel; + unsigned int imageHgtXel; + + /* We have to deal with the awkward case that the printed pixels are + not square. We match up the aspect ratio of the image in _pixels_ + and the aspect ratio of the page in _pixels_. But only the ratio + matters; we don't care what the absolute size of the pixels is. + And that's good, because if the user didn't specify xsize/ysize, we + don't know the absolute size in pixels. In that case, fortunately, + the pixels are guaranteed to be square so we can just pretend it is + one point per pixel and get the right result. + */ + + if (cmdline.xsize && cmdline.ysize) { + imageWidXel = cmdline.xsize; + imageHgtXel = cmdline.ysize; } else { - unsigned int outputWidth, outputHeight; - if (cmdline.xsize) { - /* He gave xsize and ysize, so that's the output size */ - outputWidth = cmdline.xsize; - outputHeight = cmdline.ysize; - } else { - /* Well then we'll just use his (or default) xmax, ymax */ - outputWidth = cmdline.xmax; - outputHeight = cmdline.ymax; - } + /* Pixels are square, so it doesn't matter what the resolution + is; just call it one pixel per point. + */ + imageWidXel = imageWidPt; + imageHgtXel = imageHgtPt; - if (inputHeight > inputWidth && outputHeight > outputWidth) + if (imageHgtXel >= imageWidXel && cmdline.ymax >= cmdline.xmax) { + /* Both image and page are higher than wide, so no rotation */ retval = PORTRAIT; - else if (inputHeight < inputWidth && - outputHeight < outputWidth) + } else if (imageHgtXel < imageWidXel && + cmdline.ymax < cmdline.xmax) { + /* Both image and page are wider than high, so no rotation */ retval = PORTRAIT; - else + } else { + /* Image and pixel have opposite aspect ratios, so rotate + for best fit. + */ retval = LANDSCAPE; + } } } return retval; diff --git a/converter/pbm/brushtopbm.c b/converter/pbm/brushtopbm.c index 0cffaa4d..c50fe8a1 100644 --- a/converter/pbm/brushtopbm.c +++ b/converter/pbm/brushtopbm.c @@ -1,4 +1,4 @@ -/* brushtopbm.c - read a doodle brush file and write a portable bitmap +/* brushtopbm.c - read a doodle brush file and write a PBM image ** ** Copyright (C) 1988 by Jef Poskanzer. ** @@ -12,96 +12,100 @@ #include "pbm.h" -static void getinit ARGS(( FILE* file, int* colsP, int* rowsP )); -static bit getbit ARGS(( FILE* file )); +#define HEADERSIZE 16 /* 16 is just a guess at the header size */ -int -main( argc, argv ) - int argc; - char* argv[]; - { - FILE* ifp; - bit* bitrow; - register bit* bP; - int rows, cols, padright, row, col; - - - pbm_init( &argc, argv ); - - if ( argc > 2 ) - pm_usage( "[brushfile]" ); - - if ( argc == 2 ) - ifp = pm_openr( argv[1] ); - else - ifp = stdin; - - getinit( ifp, &cols, &rows ); - - pbm_writepbminit( stdout, cols, rows, 0 ); - bitrow = pbm_allocrow( cols ); - - /* Compute padding to round cols up to the next multiple of 16. */ - padright = ( ( cols + 15 ) / 16 ) * 16 - cols; - - for ( row = 0; row < rows; ++row ) - { - /* Get data. */ - for ( col = 0, bP = bitrow; col < cols; ++col, ++bP ) - *bP = getbit( ifp ); - /* Discard line padding. */ - for ( col = 0; col < padright; ++col ) - (void) getbit( ifp ); - /* Write row. */ - pbm_writepbmrow( stdout, bitrow, cols, 0 ); - } - - pm_close( ifp ); - pm_close( stdout ); - - exit( 0 ); - } -static int item, bitsperitem, bitshift; +static void +getinit(FILE * const ifP, + unsigned int * const colsP, + unsigned int * const rowsP) { + + unsigned char header[HEADERSIZE]; + size_t bytesRead; + + bytesRead = fread(header, sizeof(header), 1, ifP); + if (bytesRead !=1) + pm_error("Error reading header"); + + if (header[0] != 1) + pm_error("bad magic number 1"); + if (header[1] != 0) + pm_error("bad magic number 2"); + + *colsP = (header[2] << 8) + header[3]; /* Max 65535 */ + *rowsP = (header[4] << 8) + header[5]; /* Max 65535 */ +} + + static void -getinit( file, colsP, rowsP ) - FILE* file; - int* colsP; - int* rowsP; - { - int i; - - if ( getc( file ) != 1 ) - pm_error( "bad magic number 1" ); - if ( getc( file ) != 0 ) - pm_error( "bad magic number 2" ); - *colsP = getc( file ) << 8; - *colsP += getc( file ); - *rowsP = getc( file ) << 8; - *rowsP += getc( file ); - bitsperitem = 8; - - /* Junk rest of header. */ - for ( i = 0; i < 10; ++i ) /* 10 is just a guess at the header size */ - (void) getc( file ); - } +validateEof(FILE * const ifP) { + + int rc; + rc = getc(ifP); + if (rc != EOF) + pm_message("Extraneous data at end of file"); +} + + +/* + The routine for converting the raster closely resembles the pbm + case of pnminvert. Input is padded up to 16 bit border. + afu December 2013 + */ + + -static bit -getbit( file ) - FILE* file; - { - bit b; - - if ( bitsperitem == 8 ) - { - item = getc( file ); - bitsperitem = 0; - bitshift = 7; - } - ++bitsperitem; - b = ( ( item >> bitshift) & 1 ) ? PBM_WHITE : PBM_BLACK; - --bitshift; - return b; +int +main(int argc, const char ** argv) { + + FILE * ifP; + bit * bitrow; + unsigned int rows, cols, row; + + pm_proginit(&argc, argv); + + if (argc-1 > 0) { + ifP = pm_openr(argv[1]); + if (argc-1 > 1) + pm_error("Too many arguments (%u). " + "The only argument is the brush file name.", argc-1); + } else + ifP = stdin; + + getinit(ifP, &cols, &rows); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols + 16); + + for (row = 0; row < rows; ++row) { + unsigned int const inRowBytes = ((cols + 15) / 16) * 2; + unsigned int i; + size_t bytesRead; + + bytesRead = fread (bitrow, 1, inRowBytes, ifP); + if (bytesRead != inRowBytes) + pm_error("Error reading a row of data from brushfile"); + + for (i = 0; i < inRowBytes; ++i) + bitrow[i] = ~bitrow[i]; + + /* Clean off remainder of fractional last character */ + if (cols % 8 > 0) { + unsigned int const colChars = pbm_packed_bytes(cols); + bitrow[colChars-1] >>= 8 - cols % 8; + bitrow[colChars-1] <<= 8 - cols % 8; + } + + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } + + validateEof(ifP); + + pm_close(ifP); + pm_close(stdout); + + return 0; +} diff --git a/converter/pbm/pbmtoepsi.c b/converter/pbm/pbmtoepsi.c index 6d2065dc..87985a1f 100644 --- a/converter/pbm/pbmtoepsi.c +++ b/converter/pbm/pbmtoepsi.c @@ -16,19 +16,24 @@ ** implied warranty. */ +/* + * + * Official guide from Adobe: + * + * Encapsulated PostScript File Format Specification + * http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf + * +*/ + #include "pm_c_util.h" #include "pbm.h" #include "shhopt.h" -#if !defined(MAXINT) -#define MAXINT (0x7fffffff) -#endif - struct cmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input files */ + const char *inputFileName; unsigned int dpiX; /* horiz component of DPI option */ unsigned int dpiY; /* vert component of DPI option */ @@ -40,8 +45,9 @@ struct cmdlineInfo { static void -parse_dpi(char * const dpiOpt, - unsigned int * const dpiXP, unsigned int * const dpiYP) { +parseDpi(char * const dpiOpt, + unsigned int * const dpiXP, + unsigned int * const dpiYP) { char *dpistr2; unsigned int dpiX, dpiY; @@ -72,7 +78,7 @@ parse_dpi(char * const dpiOpt, static void -parseCommandLine(int argc, char ** const argv, +parseCommandLine(int argc, const char ** const argv, struct cmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that @@ -97,48 +103,58 @@ parseCommandLine(int argc, char ** const argv, 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, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (dpiOptSpec) - parse_dpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); + parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); else cmdlineP->dpiX = cmdlineP->dpiY = 72; if ((argc-1) > 1) - pm_error("Too many arguments (%d). Only argument is input filespec", + pm_error("Too many arguments (%d). Only argument is input file name", argc-1); if (argc-1 == 0) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; } static void -findPrincipalImage(bit ** const bits, - int const rows, - int const cols, - int * const topP, - int * const bottomP, - int * const leftP, - int * const rightP) { +findPrincipalImage(bit ** const bits, + unsigned int const rows, + unsigned int const cols, + unsigned int * const topP, + unsigned int * const bottomP, + unsigned int * const leftP, + unsigned int * const rightP) { +/*---------------------------------------------------------------------------- + Find the foreground image on a white background. + + Find the image in the pixels bits[][], which is 'rows' rows by + 'cols' columns. - int top, bottom, left, right; - int row; + Return the boundaries of the foreground image as *topP, *bottomP, *leftP, + and *rightP. + + If the image is all white, consider the entire image foreground. +-----------------------------------------------------------------------------*/ + unsigned int top, bottom, left, right; + unsigned int row; /* Initial values */ - top = MAXINT; - bottom = -MAXINT; - left = MAXINT; - right = -MAXINT; + top = rows; + bottom = 0; + left = cols; + right = 0; - for (row = 0; row < rows; row++) { - int col; - for (col = 0; col < cols; col++) { + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; ++col) { if (bits[row][col] == PBM_BLACK) { if (row < top) top = row; @@ -152,16 +168,19 @@ findPrincipalImage(bit ** const bits, } } - if(bottom == -MAXINT) { /* No black pixels encountered */ + if (top > bottom) { + /* No black pixels encountered */ pm_message("Blank page"); - top = left = 0; - bottom = rows-1; right = cols-1; - } + top = 0; + left = 0; + bottom = rows - 1; + right = cols - 1; + } - *topP = top; + *topP = top; *bottomP = bottom; - *leftP = left; - *rightP = right; + *leftP = left; + *rightP = right; } @@ -190,7 +209,8 @@ eightPixels(bit ** const bits, /*---------------------------------------------------------------------------- Compute a byte that represents the 8 pixels starting at Column 'col' of row 'row' of the raster 'bits'. The most significant bit of the result - represents the leftmost pixel, with 1 meaning black. + represents the leftmost pixel, with 1 meaning black. (Note that this is + the opposite of Postscript.) The row is 'cols' columns wide, so fill on the right with white if there are not eight pixels in the row starting with Column 'col'. @@ -212,23 +232,23 @@ eightPixels(bit ** const bits, int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { struct cmdlineInfo cmdline; - FILE *ifP; - bit **bits; + FILE * ifP; + bit ** bits; int rows, cols; - int top, bottom, left, right; + unsigned int top, bottom, left, right; /* boundaries of principal part of image -- i.e. excluding white borders */ - pbm_init( &argc, argv ); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); - bits = pbm_readpbm( ifP, &cols, &rows ); + ifP = pm_openr(cmdline.inputFileName); + bits = pbm_readpbm(ifP, &cols, &rows); pm_close(ifP); findPrincipalImage(bits, rows, cols, &top, &bottom, &left, &right); @@ -244,24 +264,26 @@ main(int argc, char * argv[]) { right - left + 1, bottom - top + 1, bottom - top + 1); for (row = top; row <= bottom; row++) { - int col; - int outChars = 2; - printf("%% "); + unsigned int col; + unsigned int outChars; + printf("%% "); + + outChars = 2; /* initial value */ for (col = left; col <= right; col += 8) { if (outChars == 72) { - printf("\n%% "); - outChars = 2; - } + printf("\n%% "); + outChars = 2; + } printf("%02x", eightPixels(bits, row, col, cols)); outChars += 2; - } - if (outChars > 0) + } + if (outChars > 0) printf("\n"); } printf("%%%%EndImage\n"); printf("%%%%EndPreview\n"); } - exit(0); + return 0; } diff --git a/doc/HISTORY b/doc/HISTORY index e08a3e76..2dc6371b 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -4,11 +4,21 @@ Netpbm. CHANGE HISTORY -------------- -13.12.26 BJH Release 10.65.06 +13.12.26 BJH Release 10.65.00 - pamgauss: Fix typo in message. + pamfunc: add -changemaxval. + + pgmkernel: add -maxval. + + Recognize SIGPWR on systems that have it in messages + about signal received. -13.12.15 BJH Release 10.65.05 + pstopnm: More rational default for landscape/portrait choice. + In particular, if the image or page is square, image will always + be in portrait (not rotated). + + brushtopbm: check for read errors, extraneous data after apparent + end of image. pnmtops: Fix spurious blank line in asciihex encoding of the image raster. Probably harmless. Introduced in 10.56 @@ -17,6 +27,19 @@ CHANGE HISTORY pnmtops: Fix crash with 12 bits per sample. Introduced in 10.53 (December 2010). Thanks Prophet of the Way <afu@wta.att.ne.jp>. + pnmtops: Fix bug: wrong output with -ascii85. Introduced in + 10.63 (June 2013). + + pnmtops: Fix bug: wrong output with -rle. Introduced in + 10.63 (June 2013). + + pnmtops: Fix bug: program hangs if it inherits lots of open + files. Introduced in 10.56 (September 2011). + + pnmtops: Fix bug: fails with message about waitpid() failing + if invoked with SIGCHLD ignored. Introduced in 10.56 + (September 2011). + pbmtoepsi: fix handling of all-white image. Always broken. Thanks Prophet of the Way <afu@wta.att.ne.jp>. @@ -30,35 +53,30 @@ CHANGE HISTORY > 25:1. Thanks Prophet of the Way <afu@wta.att.ne.jp>. Always broken. -13.11.24 BJH Release 10.64.04 - - pnmtops: Fix bug: wrong output with -ascii85. Introduced in - 10.63 (June 2013). - - pnmtops: Fix bug: wrong output with -rle. Introduced in - 10.63 (June 2013). - - pnmtops: Fix bug: fails with message about waitpid() failing - if invoked with SIGCHLD ignored. Introduced in 10.56 - (September 2011). + pgmkernel: fix some pixels 1 less than they should be. -13.11.12 BJH Release 10.64.03 - - pnmtops: Fix bug: closes Standard Error. Introduced in - 10.64.02 (today). + pamgauss: Fix typo in message. -13.11.12 BJH Release 10.64.02 + Fix wild pointer dereference when memory allocation for a string + fails. Broken since 10.36 (September 2006). - pnmtops: Fix bug: program hangs if it inherits lots of open - files. Introduced in 10.56 (September 2011). + Build for big-endian machines: fix syntax error so it compiles. + Introduced in 10.63 (June 2013). Fix compile failure on system such as OpenBSD that don't have SIGWINCH and SIGIO. Broken since 10.49 (December 2009). -13.10.06 BJH Release 10.64.01 + Build: Use SSE2 vector instructions when compiling with Clang, + as done already with GCC. - Build for big-endian machines: fix syntax error so it compiles. - Introduced in 10.63 (June 2013). + Build: Use <emmintrin.h> interface for SSE intrinsics + instead of GCC-specific versions. Thanks Prophet of the Way + <afu@wta.att.ne.jp>. + + Build on system without vasprintf (not GNU libc): fix compiler + warning. + + Apple build: use vasprintf. 13.09.28 BJH Release 10.64.00 diff --git a/editor/pamflip/Makefile b/editor/pamflip/Makefile index 497c5379..83e961a7 100644 --- a/editor/pamflip/Makefile +++ b/editor/pamflip/Makefile @@ -5,6 +5,8 @@ endif SUBDIR = editor/pamflip VPATH=.:$(SRCDIR)/$(SUBDIR) +default: all + include $(BUILDDIR)/config.mk SUBDIRS = @@ -21,10 +23,12 @@ OBJECTS = $(PAMFLIP_OBJECTS) MERGE_OBJECTS = $(OBJECTS:%.o=%.o2) +include $(SRCDIR)/common.mk + .PHONY: all all: $(BINARIES) $(SUBDIRS:%=%/all) -include $(SRCDIR)/common.mk +pamflip_sse.o pamflip_sse.o2: CFLAGS_TARGET = $(CFLAGS_SSE) pamflip: $(PAMFLIP_OBJECTS) $(NETPBMLIB) $(LIBOPT) $(LD) -o $@ $(PAMFLIP_OBJECTS) \ diff --git a/editor/pamflip/pamflip_sse.c b/editor/pamflip/pamflip_sse.c index 5a256f9d..eccbe965 100644 --- a/editor/pamflip/pamflip_sse.c +++ b/editor/pamflip/pamflip_sse.c @@ -28,7 +28,11 @@ #include "pamflip_sse.h" -#if HAVE_GCC_SSE2 && defined(__SSE2__) +/* Note that WANT_SSE implies the user expects SSE to be available + (i.e. <emmintrin.h> exists). +*/ + +#if WANT_SSE && defined(__SSE2__) /*---------------------------------------------------------------------------- This is a specialized routine for row-for-column PBM transformations. @@ -68,6 +72,8 @@ possibility. -----------------------------------------------------------------------------*/ +#include <emmintrin.h> + typedef char v16qi __attribute__ ((vector_size (16))); typedef int v4di __attribute__ ((vector_size (16))); @@ -82,10 +88,23 @@ typedef int v4di __attribute__ ((vector_size (16))); variable must be vector from the beginning. Changes for your local system are okay, but if you intend to - publish the them, please specify the compiler version you used. + publish them, please specify the compiler version you used. + + This code has been tested on gcc versions 4.2.0, 4.2.4, 4.3.2, + 4.4.3, 4.4.4, 4.5.0, 4.5.2, 4.6.0 and 4.6.1 clang versions + 3.0, 3.2, 3.3. + + We use SSE instructions in "_mm_" form in favor of "__builtin_". + In GCC the "__builtin_" form is documented but "_mm_" is not. + Former versions of this source file used "__builtin_". This was + changed to make possible compilation with clang. + + _mm_slli_epi32 : __builtin_ia32_pslldi128 + _mm_cmpeq_epi8 : __builtin_ia32_pcmpeqb128 + _mm_movemask_epi8 : __builtin_ia32_pmovmskb128 + + The conversion requires <emmintrin.h> . - This code has been tested on gcc versions: 4.2.0, 4.2.4, 4.3.2, - 4.4.3, 4.4.4 and 4.5.0 . */ @@ -133,9 +152,10 @@ transpose16Bitrows(unsigned int const cols, block[12][col8], block[13][col8], block[14][col8], block[15][col8] }; - register v16qi const compare =__builtin_ia32_pcmpeqb128(vReg,zero128); + register __m128i const compare = + _mm_cmpeq_epi8((__m128i)vReg, (__m128i)zero128); - if (__builtin_ia32_pmovmskb128(compare) != 0xffff) { + if (_mm_movemask_epi8(compare) != 0xffff) { /* There is some black content in this block; write to outplane */ @@ -147,10 +167,10 @@ transpose16Bitrows(unsigned int const cols, for (i = 0; i < 7; ++i) { /* GCC (>=4.2) automatically unrolls this loop */ outplane[outrow++][outcol16] = - __builtin_ia32_pmovmskb128(vReg); - vReg = (v16qi)__builtin_ia32_pslldi128 ((v4di)vReg, 1); + _mm_movemask_epi8((__m128i)vReg); + vReg = (v16qi)_mm_slli_epi32((__m128i)vReg, 1); } - outplane[outrow][outcol16] = __builtin_ia32_pmovmskb128(vReg); + outplane[outrow][outcol16] = _mm_movemask_epi8((__m128i)vReg); } else { /* The block is completely white; skip. */ } @@ -391,12 +411,12 @@ pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP, pbm_freearray(outplane, outpamP->height + 7); pbm_freearray(inrow, 16); } -#else /* SSE functions exist */ +#else /* WANT_SSE */ void pamflip_transformRowsToColumnsPbmSse(const struct pam * const inpamP, const struct pam * const outpamP, - struct xformCore const xformCore) { + struct xformCore const xformCore) { /* Nobody is supposed to call this */ assert(false); diff --git a/editor/pamfunc.c b/editor/pamfunc.c index 2f6ac682..5945b82d 100644 --- a/editor/pamfunc.c +++ b/editor/pamfunc.c @@ -13,8 +13,8 @@ multiply/divide where possible. Especially when multiplying by an integer. - 2) For multiply/divide, give option of simply changing the maxval and - leaving the raster alone. + 2) speed up by not transforming the raster in the idempotent cases + (e.g. multiply by one). ******************************************************************************/ @@ -23,7 +23,7 @@ #include "shhopt.h" #include "pam.h" -enum function { +enum Function { FN_MULTIPLY, FN_DIVIDE, FN_ADD, @@ -42,22 +42,23 @@ enum function { a "max" function. */ -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespec of input file */ - enum function function; + const char * inputFileName; + enum Function function; union { - float multiplier; - float divisor; - int adder; - int subtractor; + float multiplier; + float divisor; + int adder; + int subtractor; unsigned int max; unsigned int min; unsigned int mask; unsigned int shiftCount; } u; + unsigned int changemaxval; unsigned int verbose; }; @@ -80,8 +81,8 @@ parseHex(const char * const hexString) { static void -parseCommandLine(int argc, char ** const argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, const char ** const argv, + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -126,13 +127,16 @@ parseCommandLine(int argc, char ** const argv, &shiftleftSpec, 0); OPTENT3(0, "shiftright", OPT_UINT, &cmdlineP->u.shiftCount, &shiftrightSpec, 0); - OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, + 0); + OPTENT3(0, "changemaxval", OPT_FLAG, NULL, &cmdlineP->changemaxval, + 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, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (multiplierSpec + divisorSpec + adderSpec + subtractorSpec + @@ -186,16 +190,17 @@ parseCommandLine(int argc, char ** const argv, argc-1); if (argc-1 < 1) - cmdlineP->inputFilespec = "-"; + cmdlineP->inputFileName = "-"; else - cmdlineP->inputFilespec = argv[1]; + cmdlineP->inputFileName = argv[1]; + free(option_def); } static bool -isDyadicMaskFunction(enum function const fn) { +isDyadicMaskFunction(enum Function const fn) { return (fn == FN_AND || fn == FN_OR || fn == FN_XOR); } @@ -203,7 +208,7 @@ isDyadicMaskFunction(enum function const fn) { static bool -isMaskFunction(enum function const fn) { +isMaskFunction(enum Function const fn) { return (isDyadicMaskFunction(fn) || fn == FN_NOT); } @@ -211,7 +216,7 @@ isMaskFunction(enum function const fn) { static bool -isShiftFunction(enum function const fn) { +isShiftFunction(enum Function const fn) { return (fn == FN_SHIFTLEFT || fn == FN_SHIFTRIGHT); } @@ -219,7 +224,7 @@ isShiftFunction(enum function const fn) { static bool -isBitstringFunction(enum function const fn) { +isBitstringFunction(enum Function const fn) { return isMaskFunction(fn) || isShiftFunction(fn); } @@ -227,7 +232,7 @@ isBitstringFunction(enum function const fn) { static void -validateFunction(struct cmdlineInfo const cmdline, +validateFunction(struct CmdlineInfo const cmdline, const struct pam * const pamP) { if (isBitstringFunction(cmdline.function)) { @@ -259,7 +264,58 @@ validateFunction(struct cmdlineInfo const cmdline, static void -applyFunction(struct cmdlineInfo const cmdline, +planTransform(struct CmdlineInfo const cmdline, + sample const inputMaxval, + sample * const outputMaxvalP, + bool * const mustChangeRasterP) { +/*---------------------------------------------------------------------------- + Plan the transform described by 'cmdline', given the maxval of the input + image is 'inputMaxval. + + The plan just consists of whether to change the maxval or the raster. + Some multiplications and divisions can be achieved just by changing the + maxval and leaving the samples in the raster alone. +-----------------------------------------------------------------------------*/ + if (cmdline.changemaxval) { + /* User allows us to change the maxval, if that makes it easier */ + if (cmdline.function == FN_MULTIPLY || cmdline.function == FN_DIVIDE) { + float const multiplier = + cmdline.function == FN_MULTIPLY ? cmdline.u.multiplier : + (1/cmdline.u.divisor); + + float const neededMaxval = inputMaxval / multiplier; + + if (neededMaxval + 0.5 < inputMaxval) { + /* Lowering the maxval might make some of the sample values + higher than the maxval, so we'd have to modify the raster + to clip them. + */ + *outputMaxvalP = inputMaxval; + *mustChangeRasterP = true; + } else if (neededMaxval > PAM_OVERALL_MAXVAL) { + *outputMaxvalP = inputMaxval; + *mustChangeRasterP = true; + } else { + *outputMaxvalP = ROUNDU(neededMaxval); + *mustChangeRasterP = false; + } + } else { + *outputMaxvalP = inputMaxval; + *mustChangeRasterP = true; + } + } else { + *outputMaxvalP = inputMaxval; + *mustChangeRasterP = true; + } + if (*outputMaxvalP != inputMaxval) + pm_message("Changing maxval to %u because of -changemaxval", + (unsigned)*outputMaxvalP); +} + + + +static void +applyFunction(struct CmdlineInfo const cmdline, struct pam const inpam, struct pam const outpam, tuple * const inputRow, @@ -275,10 +331,10 @@ applyFunction(struct cmdlineInfo const cmdline, divide, both cmdline.u.divisor and oneOverDivisor are meaningless. */ - int col; + unsigned int col; for (col = 0; col < inpam.width; ++col) { - int plane; + unsigned int plane; for (plane = 0; plane < inpam.depth; ++plane) { sample const inSample = inputRow[col][plane]; sample outSample; /* Could be > maxval */ @@ -330,21 +386,22 @@ applyFunction(struct cmdlineInfo const cmdline, int -main(int argc, char *argv[]) { +main(int argc, const char *argv[]) { FILE * ifP; tuple * inputRow; /* Row from input image */ tuple * outputRow; /* Row of output image */ - int row; - struct cmdlineInfo cmdline; + unsigned int row; + struct CmdlineInfo cmdline; struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ + bool mustChangeRaster; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFileName); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); @@ -355,16 +412,21 @@ main(int argc, char *argv[]) { outpam = inpam; /* Initial value -- most fields should be same */ outpam.file = stdout; + planTransform(cmdline, inpam.maxval, &outpam.maxval, &mustChangeRaster); + pnm_writepaminit(&outpam); outputRow = pnm_allocpamrow(&outpam); - for (row = 0; row < inpam.height; row++) { + for (row = 0; row < inpam.height; ++row) { pnm_readpamrow(&inpam, inputRow); - applyFunction(cmdline, inpam, outpam, inputRow, outputRow); + if (mustChangeRaster) { + applyFunction(cmdline, inpam, outpam, inputRow, outputRow); - pnm_writepamrow(&outpam, outputRow); + pnm_writepamrow(&outpam, outputRow); + } else + pnm_writepamrow(&outpam, inputRow); } pnm_freepamrow(outputRow); pnm_freepamrow(inputRow); @@ -374,3 +436,5 @@ main(int argc, char *argv[]) { return 0; } + + diff --git a/editor/pnmshear.c b/editor/pnmshear.c index 657f265d..99fa3026 100644 --- a/editor/pnmshear.c +++ b/editor/pnmshear.c @@ -1,4 +1,4 @@ -/* pnmshear.c - read a portable anymap and shear it by some angle + /* pnmshear.c - read a portable anymap and shear it by some angle ** ** Copyright (C) 1989, 1991 by Jef Poskanzer. ** @@ -17,6 +17,7 @@ #include <string.h> #include "pm_c_util.h" +#include "mallocvar.h" #include "ppm.h" #include "pnm.h" #include "shhopt.h" @@ -24,11 +25,13 @@ #define SCALE 4096 #define HALFSCALE 2048 -struct cmdline_info { + + +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char * input_filespec; /* Filespec of input file */ + const char * inputFileName; /* Name of input file */ double angle; /* requested shear angle, in radians */ unsigned int noantialias; /* -noantialias option */ const char * background; /* NULL if none */ @@ -37,15 +40,17 @@ struct cmdline_info { static void -parseCommandLine(int argc, char ** argv, - struct cmdline_info *cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo *cmdlineP) { optStruct3 opt; unsigned int option_def_index = 0; - optEntry *option_def = malloc(100*sizeof(optEntry)); + optEntry * option_def; unsigned int backgroundSpec; + MALLOCARRAY(option_def, 100); + OPTENT3(0, "noantialias", OPT_FLAG, NULL, &cmdlineP->noantialias, 0); OPTENT3(0, "background", OPT_STRING, &cmdlineP->background, &backgroundSpec, 0); @@ -54,7 +59,7 @@ parseCommandLine(int argc, char ** argv, opt.short_allowed = FALSE; opt.allowNegNum = TRUE; - pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); if (!backgroundSpec) cmdlineP->background = NULL; @@ -68,15 +73,16 @@ parseCommandLine(int argc, char ** argv, pm_error("Angle argument is not a valid floating point number: " "'%s'", argv[1]); if (argc-1 < 2) - cmdlineP->input_filespec = "-"; + cmdlineP->inputFileName = "-"; else { - cmdlineP->input_filespec = argv[2]; + cmdlineP->inputFileName = argv[2]; if (argc-1 > 2) pm_error("too many arguments (%d). " "The only arguments are shear angle and filespec.", argc-1); } } + free(option_def); } @@ -200,7 +206,7 @@ backgroundColor(const char * const backgroundColorName, int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { FILE * ifP; xel * xelrow; @@ -212,13 +218,13 @@ main(int argc, char * argv[]) { xelval maxval, newmaxval; double shearfac; - struct cmdline_info cmdline; + struct CmdlineInfo cmdline; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.input_filespec); + ifP = pm_openr(cmdline.inputFileName); pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); xelrow = pnm_allocrow(cols); @@ -256,7 +262,7 @@ main(int argc, char * argv[]) { shearCols = (rows - row) * shearfac; shearRow(xelrow, cols, newxelrow, newcols, - shearCols, format, bgxel, !cmdline.noantialias); + shearCols, format, bgxel, !cmdline.noantialias); pnm_writepnmrow(stdout, newxelrow, newcols, newmaxval, newformat, 0); } @@ -266,3 +272,6 @@ main(int argc, char * argv[]) { return 0; } + + + diff --git a/generator/pamgauss.c b/generator/pamgauss.c index 13fe8ea1..82c340fa 100644 --- a/generator/pamgauss.c +++ b/generator/pamgauss.c @@ -11,7 +11,7 @@ -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -25,8 +25,8 @@ struct cmdlineInfo { static void -parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Convert program invocation arguments (argc,argv) into a format the program can use easily, struct cmdlineInfo. Validate arguments along @@ -57,7 +57,7 @@ parseCommandLine(int argc, char ** argv, 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, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (!tupletypeSpec) @@ -101,6 +101,7 @@ parseCommandLine(int argc, char ** argv, pm_error("height argument must be a positive number. You " "specified '%s'", argv[2]); } + free(option_def); } @@ -159,15 +160,15 @@ imageNormalizer(struct pam * const pamP, int -main(int argc, char **argv) { +main(int argc, const char **argv) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; struct pam pam; int row; double normalizer; tuplen * tuplerown; - pnm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); diff --git a/generator/pgmkernel.c b/generator/pgmkernel.c index b741d596..4f40f003 100644 --- a/generator/pgmkernel.c +++ b/generator/pgmkernel.c @@ -1,8 +1,8 @@ -/* pgmkernel.c - generate a portable graymap convolution kernel +/* pgmkernel.c - generate a PGM convolution kernel ** -** Creates a Portable Graymap file containing a convolution filter -** with max value = 255 and minimum value > 127 that can be used as a -** smoothing kernel for pnmconvol. +** Creates a PGM image containing a convolution filter with max value = 255 +** and minimum value > 127 that can be used as a smoothing kernel for +** pnmconvol. ** ** Copyright (C) 1992 by Alberto Accomazzi, Smithsonian Astrophysical ** Observatory. @@ -16,76 +16,224 @@ */ #include <math.h> -#include "pgm.h" +#include "pm_c_util.h" +#include "shhopt.h" #include "mallocvar.h" +#include "pgm.h" -int -main ( argc, argv ) - int argc; - char *argv[]; -{ - register int i, j; - int argn = 1, ixsize, iysize, maxval = 255; - double fxsize = 0.0, fysize = 0.0, w = 6.0, kxcenter, kycenter, - tmax = 0, *fkernel; - const char *usage = "[-weight f] width [height]"; - - pgm_init( &argc, argv ); - - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) - { - if ( pm_keymatch( argv[argn], "-weight", 2 )) { - if (++argn >= argc) - pm_usage( usage ); - else if (sscanf(argv[argn], "%lf", &w) != 1) - pm_usage( usage ); - } - else - pm_usage( usage ); - argn++; - } - if (argn == argc) - pm_usage( usage ); - - if (sscanf(argv[argn], "%lf", &fxsize) != 1) - pm_error( "error reading input kernel x size, (%s)\n", argv[argn]); - ++argn; - if (argn == argc - 1) { - if (sscanf(argv[argn], "%lf", &fysize) != 1) - pm_error( "error reading input kernel y size, (%s)\n", argv[argn]); +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + unsigned int cols; + unsigned int rows; + float weight; + gray maxval; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Convert program invocation arguments (argc,argv) into a format the + program can use easily, struct cmdlineInfo. Validate arguments along + the way and exit program with message if invalid. + + Note that some string information we return as *cmdlineP is in the storage + argv[] points to. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to OptParseOptions2 on how to parse our options. + */ + optStruct3 opt; + + unsigned int weightSpec, maxvalSpec; + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "weight", OPT_FLOAT, &cmdlineP->weight, + &weightSpec, 0); + OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval, + &maxvalSpec, 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 (!weightSpec) + cmdlineP->weight = 6.0; + + if (cmdlineP->weight < 0.0) + pm_error("-weight cannot be negative. You specified %f", + cmdlineP->weight); + + if (!maxvalSpec) + cmdlineP->maxval = PGM_MAXMAXVAL; + + if (cmdlineP->maxval > PGM_OVERALLMAXVAL) + pm_error("-maxval is too large: %u. Maximum is %u", + cmdlineP->maxval, PGM_OVERALLMAXVAL); + + if (cmdlineP->maxval == 0) + pm_error("-maxval cannot be zero"); + + if (argc-1 < 1) + pm_error("Need at least one argument: size of (square) kernel"); + else if (argc-1 == 1) { + if (atoi(argv[1]) <= 0) + pm_error("Dimension must be a positive number. " + "You specified '%s'", argv[1]); + cmdlineP->cols = atoi(argv[1]); + cmdlineP->rows = atoi(argv[1]); + } else if (argc-1 == 2) { + if (atoi(argv[1]) <= 0) + pm_error("Width must be a positive number. " + "You specified '%s'", argv[1]); + if (atoi(argv[2]) <= 0) + pm_error("Height must be a positive number. " + "You specified '%s'", argv[2]); + cmdlineP->cols = atoi(argv[1]); + cmdlineP->rows = atoi(argv[2]); + } else + pm_error("At most two arguments allowed. " + "You specified %u", argc-1); +} + + + +static double +t(double const dx2, + double const dy2, + double const weight) { +/*---------------------------------------------------------------------------- + The t value for a pixel that is (dx, dy) pixels away from the center of + the kernel, where 'dx2' is SQR(dx) and 'dy2' is SQR(dy), if the distance is + weighted by 'weight'. +-----------------------------------------------------------------------------*/ + + return 1.0 / (1.0 + weight * sqrt(dx2 + dy2)); +} + + + +static double +tMaxAllKernel(unsigned int const cols, + unsigned int const rows, + double const weight) { +/*---------------------------------------------------------------------------- + The maximum t value over all pixels in the kernel, if the kernel is + 'cols' by 'rows' pixels and distance is weighted by 'weight'. +-----------------------------------------------------------------------------*/ + + /* It depends upon whether there is an even or odd number of rows + and columns. If both dimensions are odd, there is a pixel right + at the center, and it has the greatest t value. If both dimensions + are even, the center of the image is in the center of a 4-pixel + square and each of those 4 pixels has the greatest t value. If + one dimension is even and the other odd, the center of the kernel + is midway between two pixels, horizontally or vertically, and one + of those two pixels has the greatest t value. + */ + + double dxMax, dyMax; + + switch (cols % 2 + rows % 2) { + case 0: + dxMax = 0.5; + dyMax = 0.5; + break; + case 1: + dxMax = 0.5; + dyMax = 0.0; + break; + case 2: + dxMax = 0.0; + dyMax = 0.0; } - else if (argn == argc) - fysize = fxsize; - else - pm_usage( usage ); - - if (fxsize <= 1 || fysize <= 1) - pm_usage( usage ); - - kxcenter = (fxsize - 1) / 2.0; - kycenter = (fysize - 1) / 2.0; - ixsize = fxsize + 0.999; - iysize = fysize + 0.999; - MALLOCARRAY(fkernel, ixsize * iysize); - for (i = 0; i < iysize; i++) - for (j = 0; j < ixsize; j++) { - fkernel[i*ixsize+j] = 1.0 / (1.0 + w * sqrt((double) - (i-kycenter)*(i-kycenter)+ - (j-kxcenter)*(j-kxcenter))); - if (tmax < fkernel[i*ixsize+j]) - tmax = fkernel[i*ixsize+j]; - } - /* output PGM header + data (ASCII format only) */ - printf("P2\n%d %d\n%d\n", ixsize, iysize, maxval); + return t(SQR(dxMax), SQR(dyMax), weight); +} + + + +static void +writeKernel(FILE * const ofP, + unsigned int const cols, + unsigned int const rows, + gray const maxval, + gray ** const halfKernel, + unsigned int const halfRows) { + + unsigned int row; - for (i = 0; i < iysize; i++, printf("\n")) - for (j = 0; j < ixsize; j++) - printf(" %3d", (int)(maxval * (fkernel[i*ixsize+j] / - (2*tmax) + 0.5))); + pgm_writepgminit(stdout, cols, rows, maxval, 0); + + for (row = 0; row < halfRows; ++row) + pgm_writepgmrow(stdout, halfKernel[row], cols, maxval, 0); + + /* Now write out the same rows in reverse order. */ - exit(0); + for (; row < rows; ++row) + pgm_writepgmrow(stdout, halfKernel[rows-1-row], cols, maxval, 0); } + + +int +main(int argc, const char * argv[]) { + + struct CmdlineInfo cmdline; + unsigned int arows; + int arow; + double xcenter, ycenter; + /* row, column "number" of center of kernel */ + double tMax; + /* The maximum t value over all pixels */ + gray ** destarray; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + xcenter = ((double) cmdline.cols - 1) / 2.0; + ycenter = ((double) cmdline.rows - 1) / 2.0; + + tMax = tMaxAllKernel(cmdline.cols, cmdline.rows, cmdline.weight); + + /* Output matrix is symmetric vertically and horizontally. */ + + arows = (cmdline.rows + 1) / 2; + /* Half the number of rows. Add 1 if odd. */ + destarray = pgm_allocarray(cmdline.cols, arows); + + for (arow = 0; arow < arows; ++arow) { + double const dy2 = SQR(arow - ycenter); + + unsigned int col; + + for (col = 0; col < cmdline.cols; ++col) { + double const dx2 = SQR(col - xcenter); + + double const normalized = t(dx2, dy2, cmdline.weight) / 2 / tMax; + + destarray[arow][col] = destarray[arow][cmdline.cols - col - 1] = + ROUNDU(cmdline.maxval * (0.5 + normalized)); + } + } + + writeKernel(stdout, cmdline.cols, cmdline.rows, cmdline.maxval, + destarray, arows); + + pgm_freearray(destarray, arows); + + return 0; +} diff --git a/lib/Makefile b/lib/Makefile index 8d9b3175..6512949f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -84,13 +84,12 @@ extra_staticlib: $(EXTRA_STATICLIB) # type, but request a static library in addition. #---------------------------------------------------------------------------- -# Note that the user may have configured -I options into CPPFLAGS/CFLAGS. -CFLAGS_ALL = $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_SHLIB) \ - $(CFLAGS_PERSONAL) $(CADD) +$(LIBOBJECTS): CFLAGS_TARGET=$(CFLAGS_SHLIB) + +libpbm3.o: CFLAGS_TARGET+=$(CFLAGS_SSE) $(LIBOBJECTS): %.o: %.c importinc -# We have to get the command all on one line to avoid messy make messages - $(CC) -c $(CFLAGS_ALL) -o $@ $< + $(CC) -c $(INCLUDES) $(CFLAGS_ALL) -o $@ $< MAJ = 11 MIN = $(NETPBM_MINOR_RELEASE) diff --git a/lib/libpbm3.c b/lib/libpbm3.c index d6a953c2..020e1558 100644 --- a/lib/libpbm3.c +++ b/lib/libpbm3.c @@ -16,21 +16,28 @@ #include "pbm.h" #ifndef PACKBITS_SSE -#if HAVE_GCC_SSE2 && HAVE_GCC_BSWAP && defined(__SSE2__) +#if WANT_SSE && defined(__SSE2__) && HAVE_GCC_BSWAP #define PACKBITS_SSE 2 #else #define PACKBITS_SSE 0 #endif #endif -/* HAVE_GCC_SSE2 means we have the means to use SSE CPU facilities - to make PBM raster processing faster. GCC only. +/* WANT_SSE means we want to use SSE CPU facilities to make PBM raster + processing faster. This implies it's actually possible - i.e. the + build environment has <emmintrin.h>. - The GNU Compiler -msse2 option makes SSE/SSE2 available. - For x86-32 with MMX/SSE, "-msse2" must be explicitly given. + The GNU Compiler -msse2 option makes SSE/SSE2 available, and is + evidenced by __SSE2__. + For x86-32 with SSE, "-msse2" must be explicitly given. For x86-64 and AMD64, "-msse2" is the default (from Gcc v.4.) */ +#if PACKBITS_SSE == 2 + #include <emmintrin.h> +#endif + + void pbm_writepbminit(FILE * const fileP, int const cols, @@ -81,16 +88,28 @@ packBitsWithSse2( FILE * const fileP, PCMPGTB128 Packed CoMPare Greater Than Byte Compares 16 bytes in parallel - Result is x00 if greater than, xFF if not for each byte + Result is x00 if greater than, xFF if not for each byte + PMOVMSKB128 Packed MOVe MaSK Byte - Result is a byte of the MSBs of 16 bytes + Result is 16 bits, the MSBs of 16 bytes x00 xFF x00 xFF xFF xFF x00 x00 xFF xFF xFF xFF x00 x00 x00 x00 --> 0101110011110000B = 0x5CF0 The result is actually a 64 bit int, but the higher bits are always 0. + + We use SSE instructions in "_mm_" form in favor of "__builtin_". + In GCC the "__builtin_" form is documented but "_mm_" is not. + Former versions of this source file used "__builtin_". This was + changed to make possible compilation with clang, which does not + implement some "__builtin_" forms. + + __builtin_ia32_pcmpgtb128 : _mm_cmpgt_epi8 + __builtin_ia32_pmovmskb128 : _mm_movemask_epi8 + + The conversion requires <emmintrin.h> . */ typedef char v16qi __attribute__ ((vector_size(16))); @@ -110,11 +129,10 @@ packBitsWithSse2( FILE * const fileP, bit128.i64[1]=__builtin_bswap64( *(uint64_t*) &bitrow[col+8]); { - v16qi const compare = - __builtin_ia32_pcmpgtb128(bit128.v16, zero128); - uint16_t const blackMask = - (uint16_t) __builtin_ia32_pmovmskb128(compare); - + v16qi const compare = (v16qi) + _mm_cmpgt_epi8((__m128i)bit128.v16, (__m128i) zero128); + uint16_t const blackMask = _mm_movemask_epi8 ((__m128i)compare); + *(uint16_t *) & packedBits[col/8] = blackMask; } } @@ -128,10 +146,9 @@ packBitsWithSse2( FILE * const fileP, bit128.byte[ (i&8) + 7-(i&7) ] = bitrow[j]; { - v16qi const compare = - __builtin_ia32_pcmpgtb128( bit128.v16, zero128 ); - uint16_t const blackMask = - __builtin_ia32_pmovmskb128( compare ); + v16qi const compare = (v16qi) + _mm_cmpgt_epi8((__m128i)bit128.v16, (__m128i) zero128); + uint16_t const blackMask = _mm_movemask_epi8 ((__m128i)compare); if ( cols%16 >8 ) /* Two partial bytes */ *(uint16_t *) & packedBits[col/8] = blackMask; diff --git a/lib/libsystem.c b/lib/libsystem.c index 8db663bc..48c6f06d 100644 --- a/lib/libsystem.c +++ b/lib/libsystem.c @@ -13,6 +13,7 @@ Contributed to the public domain. =============================================================================*/ #define _XOPEN_SOURCE +#define _BSD_SOURCE /* Make SIGWINCH defined on OpenBSD */ #include <stdarg.h> #include <unistd.h> @@ -220,6 +221,18 @@ spawnProcessor(const char * const progName, static const char * signalName(unsigned int const signalClass) { +/* There are various signal classes that are not universally defined, + so we make a half-hearted attempt to determine whether they are and + not try to recognize the ones that aren't. We do this by testing + whether a macro is defind with the signal class name. That could give + a false negative, because the signal class name isn't necessarily + defined as a macro, but it's a really, really small problem to miss + one of these signal classes here, so we don't bother with all the work + it would take to do it right. + + OpenBSD does not have SIGWINCH and SIGIO in 2013. Everyone else seems + to have it. +*/ switch (signalClass) { case SIGHUP: /* POSIX.1 */ return "SIGHUP"; @@ -273,12 +286,6 @@ signalName(unsigned int const signalClass) { return "SIGVTALRM"; case SIGPROF: return "SIGPROF"; -/* Most systems have SIGWINCH and SIGIO, but at least OpenBSD, in 2013, - does not. Systems that do don't necessarily supply it as a macro, so - the following tests are not perfect, but a false negative is a really, - really, small problem, so we don't bother with all the work it would - take to do better. -*/ #ifdef SIGWINCH case SIGWINCH: return "SIGWINCH"; @@ -287,16 +294,14 @@ signalName(unsigned int const signalClass) { case SIGIO: return "SIGIO"; #endif +#ifdef SIGPWR + case SIGPWR: + return "SIGPWR"; +#endif case SIGSYS: return "SIGSYS"; default: return "???"; - - /* There are various other signal classes on some systems, but - not defined by POSIX and not on at least one system we - know of for which someone wanted to compile Netpbm. The - list includes: SIGPWR, SIGLOST, SIGINFO, SIGRTxx. - */ } } diff --git a/lib/util/Makefile b/lib/util/Makefile index 5bf1995e..28dfddfe 100644 --- a/lib/util/Makefile +++ b/lib/util/Makefile @@ -5,6 +5,8 @@ endif SUBDIR = lib/util VPATH=.:$(SRCDIR)/$(SUBDIR) +default:all + include $(BUILDDIR)/config.mk # nstring is required for asprintf(), etc. Also some systems don't have @@ -22,13 +24,14 @@ UTILOBJECTS = \ MERGE_OBJECTS = +include $(SRCDIR)/common.mk + all: $(UTILOBJECTS) -include $(SRCDIR)/common.mk +$(UTILOBJECTS): CFLAGS_TARGET=$(CFLAGS_SHLIB) $(UTILOBJECTS):%.o:%.c importinc - $(CC) -c $(INCLUDES) -DNDEBUG $(CPPFLAGS) $(CFLAGS) $(CFLAGS_SHLIB) \ - $(CFLAGS_PERSONAL) $(CADD) -o $@ $< + $(CC) -c $(INCLUDES) $(CFLAGS_ALL) -o $@ $< testnstring: test.c nstring.h nstring.o - $(CC) $(CFLAGS) $(CADD) -o $@ nstring.o $< + $(CC) $(CFLAGS_ALL) -o $@ nstring.o $< diff --git a/lib/util/nstring.c b/lib/util/nstring.c index e95d9824..bb2ba92e 100644 --- a/lib/util/nstring.c +++ b/lib/util/nstring.c @@ -134,12 +134,6 @@ #include "nstring.h" -#if (defined(__GLIBC__) || defined(__GNU_LIBRARY__)) - #define HAVE_VASPRINTF 1 -#else - #define HAVE_VASPRINTF 0 -#endif - #ifdef isdigit #undef isdigit #endif @@ -797,9 +791,12 @@ pm_asprintf(const char ** const resultP, va_list varargs; #if HAVE_VASPRINTF + int rc; va_start(varargs, fmt); - vasprintf((char **)&result, fmt, varargs); + rc = vasprintf((char **)&result, fmt, varargs); va_end(varargs); + if (rc < 0) + result = pm_strsol; #else size_t dryRunLen; @@ -811,20 +808,23 @@ pm_asprintf(const char ** const resultP, if (dryRunLen + 1 < dryRunLen) /* arithmetic overflow */ - result = NULL; + result = pm_strsol; else { size_t const allocSize = dryRunLen + 1; - result = malloc(allocSize); - if (result != NULL) { + char * buffer; + buffer = malloc(allocSize); + if (buffer != NULL) { va_list varargs; size_t realLen; va_start(varargs, fmt); - pm_vsnprintf(result, allocSize, fmt, varargs, &realLen); + pm_vsnprintf(buffer, allocSize, fmt, varargs, &realLen); assert(realLen == dryRunLen); va_end(varargs); + + result = buffer; } } #endif diff --git a/lib/util/pm_c_util.h b/lib/util/pm_c_util.h index 79897cf0..01a07657 100644 --- a/lib/util/pm_c_util.h +++ b/lib/util/pm_c_util.h @@ -83,7 +83,7 @@ #define TRUE true #endif #ifndef FALSE -#define FALSE false + #define FALSE false #endif #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) diff --git a/lib/util/vasprintf.c b/lib/util/vasprintf.c index 209827eb..e38252fa 100644 --- a/lib/util/vasprintf.c +++ b/lib/util/vasprintf.c @@ -18,9 +18,11 @@ pm_vasprintf(const char ** const resultP, char * result; #if HAVE_VASPRINTF - vasprintf(&result, format, varargs); + int rc; - if (result == NULL) + rc = vasprintf(&result, format, varargs); + + if (rc < 0) *resultP = pm_strsol; else *resultP = result; diff --git a/other/pamarith.c b/other/pamarith.c index a53029da..b64f69fb 100644 --- a/other/pamarith.c +++ b/other/pamarith.c @@ -47,7 +47,7 @@ isDyadic(enum function const function) { -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ @@ -60,7 +60,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, const char ** const argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -796,7 +796,7 @@ doUnNormalizedArith(struct pam * const inpam1P, int main(int argc, const char *argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; struct pam inpam1; struct pam inpam2; struct pam outpam; diff --git a/pm_config.in.h b/pm_config.in.h index 9459be02..fd651e3a 100644 --- a/pm_config.in.h +++ b/pm_config.in.h @@ -187,22 +187,14 @@ /* CONFIGURE: GNU Compiler extensions are used in performance critical places when available. Test whether they exist. - Turn off by defining NO_GCC_BUILTINS. - - Note that though these influence the resulting Netpbm machine code, the - compiler setting ultimately decides what instruction set the compiler uses. - If you want a generic build, check the manual and adjust CFLAGS in - config.mk accordingly. - - For example, if you want binaries that run on all Intel x86-32 - family CPUs back to 80386, adding "-march=i386" to CFLAGS in - config.mk is much better than setting NO_GCC_BUILTINS to 1. - If you want to be extra sure use: - "-march=i386 -mno-mmx -mno-sse -DNO_GCC_BUILTINS" - - Gcc uses SSE and SSE2 instructions by default for AMD/Intel x86-64. - Tinkering with "-mno-sse" is not recommended for these machines. If you - don't want SSE code, set NO_GCC_BUILTINS to 1. + Prevent the build from exploiting these extensions by defining + NO_GCC_UNIQUE. + + Before Netpbm 10.65 (December 2013), Netpbm used GCC compiler extensions + to generate SSE code in Pamflip. Starting in 10.65, Netpbm instead uses + the more standard operators defined in <emmtrins.h>. To prevent Netpbm + from explicitly using any SSE instructions, set WANT_SSE to N in + config.mk. */ /* @@ -214,7 +206,7 @@ > cc --version Apple clang version 4.0 (tags/Apple/clang-421.0.60) (based on LLVM 3.1svn) - which masquerades as GCC 4.2.1, but it does not have SSE2 function + which masquerades as GCC 4.2.1, but it does not have SSE2 operator __builtin_ia32_pcmpeqb128 . On the other hand, research by Prophet of the Way in September 2012 @@ -222,18 +214,24 @@ compiled successfully with SSE exploitation), but 3.1 does not. He did not find any mention in documentation of that change. + At least some versions of Clang that do not have __builtin_ia32_pcmpeqb128 + nonetheless have other GCC SSE2 operators, such as __builtin_ia32_pcmpgtb128. + We did not detect a pattern. + See below on compilers other than GCC that set __GNUC__: http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers */ -#if defined(__GNUC__) && !defined(__clang__) && !defined(NO_GCC_BUILTINS) +#if defined(__GNUC__) && !defined(__clang__) && !defined(NO_GCC_UNIQUE) #define GCCVERSION __GNUC__*100 + __GNUC_MINOR__ #else #define GCCVERSION 0 #endif -/* HAVE_GCC_SSE2 means the compiler has GCC builtins to directly access - SSE/SSE2 features. This is different from whether the compiler generates - code that uses these features at all. +/* HAVE_GCC_SSE2 means the compiler has all of the GCC-specific builtins to + directly access SSE/SSE2 features. This is different from whether the + compiler generates code that uses these features at all. It is also + different from whether the compiler has the more standard operators defined + in <emmintrins.h>. */ #ifndef HAVE_GCC_SSE2 @@ -260,10 +258,9 @@ #endif #ifndef HAVE_GCC_BSWAP -#if GCCVERSION >=403 +#if GCCVERSION >=403 || defined(__clang__) #define HAVE_GCC_BSWAP 1 /* Use __builtin_bswap32(), __builtin_bswap64() for endian conversion. - Available from GCC v 4.3 onward. NOTE: On intel CPUs this may produce the bswap operand which is not available on 80386. */ #else diff --git a/test/Execute-Tests b/test/Execute-Tests index 047cf4a3..7a1a3793 100755 --- a/test/Execute-Tests +++ b/test/Execute-Tests @@ -39,17 +39,10 @@ fi # export PBM_BINPREFIX="" export PBM_BINPREFIX=${PBM_TESTPREFIX} -# Add PBM_BINPREFIX to PATH. -# This is necessary for Netpbm programs (mosly scripts) that call -# other Netpbm programs. - -if [ ! -z $PBM_BINPREFIX ] - then - export PATH=${PBM_BINPREFIX}:$PATH -fi - -# Set srcdir, which is the directory which contains Execute-Tests -# (this script), Test-Order *.test and *.ok files. +# Set srcdir, which is the directory which contains Execute-Tests (this +# script), programs that run the test, including *.test and helpers that they +# invoke, the list of tests to run ('Test-Order'), and *.ok files that +# indicate the expected results of tests. srcdir=$(dirname $0) @@ -101,6 +94,16 @@ if [ ! -f ./testimg.ppm ] then cp -v ${srcdir}/testimg.ppm ./testimg.ppm fi +# Add PBM_BINPREFIX to PATH. +# This is necessary for Netpbm programs that call other Netpbm programs. + +if [ ! -z $PBM_BINPREFIX ] + then + export PATH=${PBM_BINPREFIX}:$PATH +fi + +export PATH=${srcdir}:$PATH + # Execute the tests, as described in the "Test-Order" file. # # Each test outputs a ".out" file, which is compared against a diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..4d44285f --- /dev/null +++ b/test/Makefile @@ -0,0 +1,24 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/.. + BUILDDIR = $(SRCDIR) +endif +SUBDIR = test +VPATH = .:$(SRCDIR)/$(SUBDIR) +include $(BUILDDIR)/config.mk + +MERGE_OBJECTS = + +PROGS = testrandom + +all: $(PROGS) + +PORTBINARIES = testrandom +OBJECTS = $(PORTBINARIES:%=%.o) + +OMIT_TEST_RULE = 1 +include $(SRCDIR)/common.mk + +distclean clean: cleanlocal +.PHONY: cleanlocal +cleanlocal: + rm -f $(PROGS) diff --git a/test/Test-Order b/test/Test-Order index 698552b9..31cd5324 100644 --- a/test/Test-Order +++ b/test/Test-Order @@ -63,6 +63,7 @@ ppmbrighten.test ppmdither.test pamedge.test ppmdim.test +pnmshear.test ppmmix.test @@ -109,6 +110,7 @@ mrf-roundtrip.test pfm-roundtrip.test png-roundtrip.test ps-roundtrip.test +ps-alt-roundtrip.test sunrast-roundtrip.test targa-roundtrip.test tiff-roundtrip.test diff --git a/test/pnmshear.ok b/test/pnmshear.ok new file mode 100644 index 00000000..d701faaf --- /dev/null +++ b/test/pnmshear.ok @@ -0,0 +1 @@ +2080980136 22 diff --git a/test/pnmshear.test b/test/pnmshear.test new file mode 100644 index 00000000..276e3e22 --- /dev/null +++ b/test/pnmshear.test @@ -0,0 +1,19 @@ +#! /bin/bash +# This script tests: pnmshear +# Also requires: pbmmake + +# Test. Should produce 2080980136 22 +${PBM_BINPREFIX}pbmmake -g 7 7 | \ + ${PBM_TESTPREFIX}pnmshear 45 -noantialias | cksum + +# Output of above, in pbm plain format +# +# P1 +# 14 7 +# 01010101111111 +# 10101011111111 +# 10101010111111 +# 11101010111111 +# 11101010101111 +# 11111010101111 +# 11111010101011 diff --git a/test/ps-alt-roundtrip.ok b/test/ps-alt-roundtrip.ok new file mode 100644 index 00000000..1cd73f75 --- /dev/null +++ b/test/ps-alt-roundtrip.ok @@ -0,0 +1,3 @@ +2425386270 41 +2425386270 41 +2916080186 235 diff --git a/test/ps-alt-roundtrip.test b/test/ps-alt-roundtrip.test new file mode 100755 index 00000000..8ce1689d --- /dev/null +++ b/test/ps-alt-roundtrip.test @@ -0,0 +1,46 @@ +#! /bin/bash +# This script tests: pbmtoepsi pbmtopsg3 pbmtolps psidtopgm pstopnm +# Also requires: gs pnmtopnm pnmcrop + +# This script is for testing alternative (or minor) utilities that +# read/write Postscript and encapsulated Postscript: +# pbmtoepsi, pbmtopsg3, pbmtolps 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. +# +# If ps-roundtrip.test succeeds and this test fails, it is most likely +# a problem with one of the minor utilities, and vice versa. + + +# Test 1. Should print: 2425386270 41 +${PBM_TESTPREFIX}pbmtopsg3 -dpi=72 testgrid.pbm \ + > ${tmpdir}/testgrid1.ps && \ +${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 -llx=0 -lly=-16 -urx=14 \ + -dpi=72 -stdout -quiet -pbm ${tmpdir}/testgrid1.ps | \ + ${PBM_BINPREFIX}pnmcrop | cksum + + +# Test 2. Should print: 2425386270 41 +${PBM_TESTPREFIX}pbmtolps -dpi 72 testgrid.pbm \ + > ${tmpdir}/testgrid2.ps && \ +${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 -dpi=72 -stdout \ + -quiet ${tmpdir}/testgrid2.ps -pbm | \ + ${PBM_BINPREFIX}pnmcrop | cksum + + +# Test 3. Should print: 2916080186 235 +# Output is pgm maxval=1 with black and white inverted. +# +${PBM_TESTPREFIX}pbmtoepsi testgrid.pbm > ${tmpdir}/testgrid.epsi && \ +xysizebps=`awk '/BeginPreview/ {print $2,$3,$4}' \ + ${tmpdir}/testgrid.epsi` && \ +awk '/^%%BeginPreview:/ { p=1; next } /^%%EndImage/ { p=0; next } \ + p==1 && /%[ \t0-9a-fA-F]+/ { print substr($0,2); next } \ + p==1 {print "!"$0}' \ + ${tmpdir}/testgrid.epsi | ${PBM_TESTPREFIX}psidtopgm $xysizebps | cksum + + +rm ${tmpdir}/testgrid[12].ps ${tmpdir}/testgrid.epsi diff --git a/test/ps-roundtrip.ok b/test/ps-roundtrip.ok index a267f7eb..0ebfb94a 100644 --- a/test/ps-roundtrip.ok +++ b/test/ps-roundtrip.ok @@ -1,3 +1,15 @@ 1926073387 101484 -2425386270 41 +1926073387 101484 +1926073387 101484 +1926073387 101484 +1926073387 101484 +2918318199 62 +2918318199 62 +2918318199 62 +2918318199 62 +2918318199 62 +2918318199 62 +2918318199 62 +1386192571 507420 +1386192571 507420 1386192571 507420 diff --git a/test/ps-roundtrip.test b/test/ps-roundtrip.test index 60ecf60a..b7aa816c 100755 --- a/test/ps-roundtrip.test +++ b/test/ps-roundtrip.test @@ -1,38 +1,70 @@ #! /bin/bash # This script tests: pnmtops pstopnm -# Also requires: pnmtopnm pamtopnm gs +# Also requires: pnmtopnm pamtopnm gs pbmmake pnmshear pnmpad pnmcat -# Test 1. Should print: 1926073387 101484 -${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn testimg.ppm \ - > ${tmpdir}/testimg.ps -xysize1=`awk '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \ - ${tmpdir}/testimg.ps` -${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize1 -stdout \ - -quiet ${tmpdir}/testimg.ps | \ - ${PBM_BINPREFIX}pnmtopnm | cksum +# Test 1. Should print: 1926073387 101484 five times +# *NOTE* Fifth iteration fails if pnmtops was compiled without zlib +# (flate compression) support. +for flag in "" "-ps" "-rle" "-ps -ascii" "-ps -flate" + do + ${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn \ + ${flag} testimg.ppm \ + > ${tmpdir}/testimg.ps + xysize1=`awk '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \ + ${tmpdir}/testimg.ps` + ${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize1 -stdout \ + -quiet ${tmpdir}/testimg.ps | \ + ${PBM_BINPREFIX}pnmtopnm | cksum + done -# Test 2. Should print: 2425386270 41 -${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn \ - testgrid.pbm > ${tmpdir}/testgrid.ps && -xysize2=`awk '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \ - ${tmpdir}/testgrid.ps` -${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize2 -stdout \ - -quiet ${tmpdir}/testgrid.ps -pbm | \ - ${PBM_BINPREFIX}pnmtopnm | cksum +# Test 2. Should print: 2918318199 62 seven times +# Test image designed to detect problems with run-length compression +# +${PBM_BINPREFIX}pbmmake -g 2 2 > ${tmpdir}/g.pbm +${PBM_BINPREFIX}pbmmake -g 8 4 | \ + ${PBM_BINPREFIX}pnmshear 45 -noantialias -background=black | \ + ${PBM_BINPREFIX}pnmpad -right 60 | \ + ${PBM_BINPREFIX}pnmcat -tb -jright - ${tmpdir}/g.pbm > ${tmpdir}/t.pbm && +for flag in "" "-rle" "-ps -rle -ascii" \ + "-bitspersample=2 -rle" "-ps -bitspersample=4 -rle" \ + "-bitspersample=8 -rle" "-ps -bitspersample=12 -rle -dict" + do + ${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn \ + ${flag} ${tmpdir}/t.pbm > ${tmpdir}/testgrid.ps && + xysize2=`awk '/BoundingBox/ {print "-xsize="$4,"-ysize="$5}' \ + ${tmpdir}/testgrid.ps` + ${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize2 -stdout \ + -quiet ${tmpdir}/testgrid.ps -pbm | \ + ${PBM_BINPREFIX}pnmtopnm | cksum + done -#Test 3. Should print: 1386192571 507420 +#Test 3. Should print: 1386192571 507420 three times +# *NOTE* Second iteration fails if pnmtops was compiled without zlib +# (flate compression) support. +# +# Special care is needed when conducting round-trips with multiple-image +# files as input. +# (1) pnmtops: -setpage is mandatory +# (2) awk: xy values are taken from the first "BoundingBox" encountered. +# Subsequent BoundingBox values are ignored. +# (3) pstopnm: input must be an ordinary file. Input from stdin +# (by pipe or input redirection: "< file" ) does not work. +# +for flag in "" "-ps" \ + "-ps -bitspersample=12 -flate -rle -vmreclaim" + do cat testimg.ppm testimg.ppm testimg.ppm testgrid.pbm testgrid.pbm | \ ${PBM_TESTPREFIX}pnmtops -nocenter -equalpixels -dpi 72 -noturn -setpage \ - > ${tmpdir}/testimg5.ps + ${flag} > ${tmpdir}/testimg5.ps xysize3=`awk '/BoundingBox/ {print "-xsize="$4,"-ysize="$5 ; exit}' \ ${tmpdir}/testimg5.ps` ${PBM_TESTPREFIX}pstopnm -xborder=0 -yborder=0 $xysize3 \ -stdout ${tmpdir}/testimg5.ps | \ ${PBM_BINPREFIX}pnmtopnm | cksum + done -#rm ${tmpdir}/testgrid.ps ${tmpdir}/testimg.ps ${tmpdir}/testimg5.ps -rm ${tmpdir}/testimg.ps ${tmpdir}/testimg5.ps -mv ${tmpdir}/testgrid.ps /tmp +rm ${tmpdir}/testgrid.ps ${tmpdir}/testimg.ps ${tmpdir}/testimg5.ps \ + ${tmpdir}/t.pbm diff --git a/buildtools/testrandom.c b/test/testrandom.c index 3f65f0d2..3f65f0d2 100644 --- a/buildtools/testrandom.c +++ b/test/testrandom.c diff --git a/urt/Makefile b/urt/Makefile index b94da1b2..0aef5290 100644 --- a/urt/Makefile +++ b/urt/Makefile @@ -5,6 +5,8 @@ endif SUBDIR = urt VPATH=.:$(SRCDIR)/$(SUBDIR) +default: all + include $(BUILDDIR)/config.mk LIBOBJECTS = Runput.o cmd_name.o \ @@ -15,6 +17,9 @@ LIBOBJECTS = Runput.o cmd_name.o \ MERGE_OBJECTS = +OMIT_URT_RULE = 1 +include $(SRCDIR)/common.mk + all: librle.a librle.a: $(LIBOBJECTS) @@ -24,11 +29,8 @@ librle.a: $(LIBOBJECTS) # Rule for objects. $(LIBOBJECTS): %.o: %.c importinc - $(CC) -c $(INCLUDES) -o $@ \ - $< $(CPPFLAGS) $(CFLAGS) $(CFLAGS_PERSONAL) $(CADD) + $(CC) -c $(INCLUDES) -o $@ $< $(CFLAGS_ALL) BINARIES = SCRIPTS = -OMIT_URT_RULE = 1 -include $(SRCDIR)/common.mk diff --git a/version.mk b/version.mk index 7f06da81..0b659594 100644 --- a/version.mk +++ b/version.mk @@ -1,4 +1,4 @@ NETPBM_MAJOR_RELEASE = 10 -NETPBM_MINOR_RELEASE = 64 -NETPBM_POINT_RELEASE = 6 +NETPBM_MINOR_RELEASE = 65 +NETPBM_POINT_RELEASE = 0 |