/* pnminvert.c - read a portable anymap and invert it ** ** Copyright (C) 1989 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "pnm.h" /* Implementation note: A suitably advanced compiler, such as Gcc 4, implements the for statements in our algorithm with instructions that do 16 bytes at a time on CPUs that have them (movdqa on x86). This is "tree vectorization." A more primitive compiler will do one byte at a time; we could change the code to use uint32_t or uint64_t and it will do four or eight bytes at a time. (But we don't think it's worth complicating the code for that). */ #define CHARBITS (sizeof(unsigned char)*8) static void invertPbm(FILE * const ifP, FILE * const ofP, int const cols, int const rows, int const format) { /*---------------------------------------------------------------------------- Invert a PBM image. Use the "packed" PBM functions for speed. -----------------------------------------------------------------------------*/ int const colChars = pbm_packed_bytes(cols); unsigned char * bitrow; unsigned int row; bitrow = pbm_allocrow_packed(cols); for (row = 0; row < rows; ++row) { unsigned int colChar; pbm_readpbmrow_packed(ifP, bitrow, cols, format); for (colChar = 0; colChar < colChars; ++colChar) bitrow[colChar] = ~ bitrow[colChar]; /* Clean off remainder of fractional last character and write */ pbm_cleanrowend_packed(bitrow, cols); pbm_writepbmrow_packed(ofP, bitrow, cols, 0); } pbm_freerow_packed(bitrow); } static void invertPnm(FILE * const ifP, FILE * const ofP, int const cols, int const rows, xelval const maxval, int const format) { xel * xelrow; unsigned int row; xelrow = pnm_allocrow(cols); for (row = 0; row < rows; ++row) { unsigned int col; pnm_readpnmrow(ifP, xelrow, cols, maxval, format); for (col = 0; col < cols; ++col) pnm_invertxel(&xelrow[col], maxval, format); pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0); } pnm_freerow(xelrow); } int main(int argc, char * argv[]) { FILE* ifP; xelval maxval; int rows, cols, format; pnm_init(&argc, argv); if (argc-1 > 1) pm_error("There is at most 1 argument - the input file name. " "You specified %d", argc-1); if (argc-1 == 1) ifP = pm_openr(argv[1]); else ifP = stdin; pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); pnm_writepnminit(stdout, cols, rows, maxval, format, 0); if (PNM_FORMAT_TYPE(format) == PBM_TYPE) /* Take fast path */ invertPbm(ifP, stdout, cols, rows, format); else /* PPM , PGM (logic also works for PBM) */ invertPnm(ifP, stdout, cols, rows, maxval, format); pm_close(ifP); pm_close(stdout); return 0; }