Index: trunk/ppImage/src/ppImageParityFlip.c
===================================================================
--- trunk/ppImage/src/ppImageParityFlip.c	(revision 24228)
+++ trunk/ppImage/src/ppImageParityFlip.c	(revision 24228)
@@ -0,0 +1,127 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ppImage.h"
+
+// Update a concept to the assumed value
+#define FIX_CONCEPT(SOURCE, NAME, TYPE, VALUE) {        \
+psMetadataItem *item = psMetadataLookup(SOURCE, NAME); \
+item->data.TYPE = VALUE; }
+
+bool ppImageParityFlip (pmConfig *config, const ppImageOptions *options, const pmFPAview *view) {
+
+    bool status;
+
+    if (!options->applyParity) return true;
+
+    // find the currently selected readout
+    pmReadout *readout = pmFPAfileThisReadout(config->files, view, "PPIMAGE.INPUT");
+
+    pmCell *cell = readout->parent;
+
+    int xParity = psMetadataLookupS32(&status, cell->concepts, "CELL.XPARITY");
+    if (!status || (xParity != -1 && xParity != 1)) {
+        psWarning("CELL.XPARITY is not set for the input cell; assuming 1.\n");
+        FIX_CONCEPT(cell->concepts, "CELL.XPARITY", S32, 1);
+        xParity = 1;
+    }
+    int yParity = psMetadataLookupS32(&status, cell->concepts, "CELL.YPARITY");
+    if (!status || (yParity != -1 && yParity != 1)) {
+        psWarning("CELL.YPARITY is not set for the input cell; assuming 1.\n");
+        FIX_CONCEPT(cell->concepts, "CELL.YPARITY", S32, 1);
+        yParity = 1;
+    }
+
+    // for this case, nothing to be done:
+    if ((xParity == 1) && (yParity == 1)) return true;
+    
+    psImage *image = readout->image;
+    psImage *var   = readout->variance;
+    psImage *mask  = readout->mask;
+
+    if (var) psAssert (image->numCols == var->numCols,  "image and variance sizes are mismatched");
+    if (var) psAssert (image->numRows == var->numRows,  "image and variance sizes are mismatched");
+    if (mask) psAssert (image->numCols == mask->numCols, "image and mask sizes are mismatched");
+    if (mask) psAssert (image->numRows == mask->numRows, "image and mask sizes are mismatched");
+
+    int Nx = image->numCols;
+    int Ny = image->numRows;
+
+    // we need working buffers for the image, variance, and mask:
+    psF32 *imrow = (psF32 *) psAlloc (Nx*sizeof(psF32));
+    psF32 *wtrow = (psF32 *) psAlloc (Nx*sizeof(psF32));
+    psImageMaskType *mkrow = (psImageMaskType *) psAlloc (Nx*sizeof(psImageMaskType));
+
+    // the three cases (+1,-1), (-1,+1), (-1,-1) should be handled independently
+    if ((xParity == -1) && (yParity == +1)) {
+	for (int iy = 0; iy < Ny; iy++) {
+	    for (int ix = 0; ix < Nx; ix++) {
+		imrow[Nx-1-ix] = image->data.F32[iy][ix];
+	    }
+	    for (int ix = 0; (var != NULL) && (ix < Nx); ix++) {
+		wtrow[Nx-1-ix] = var->data.F32[iy][ix];
+	    }
+	    for (int ix = 0; (mask != NULL) && (ix < Nx); ix++) {
+		mkrow[Nx-1-ix] = mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix];
+	    }
+	    memcpy (image->data.F32[iy], imrow, Nx*sizeof(psF32));
+	    if (var) memcpy (var->data.F32[iy],   wtrow, Nx*sizeof(psF32));
+	    if (mask) memcpy (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy], mkrow, Nx*sizeof(psImageMaskType));
+	}
+    }
+    if ((xParity == +1) && (yParity == -1)) {
+	for (int iy = 0; iy < Ny/2; iy++) {
+	    memcpy (imrow, image->data.F32[iy], Nx*sizeof(psF32));
+	    memcpy (image->data.F32[iy], image->data.F32[Ny-1-iy], Nx*sizeof(psF32));
+	    memcpy (image->data.F32[Ny-1-iy], imrow, Nx*sizeof(psF32));
+
+	    if (var) {
+		memcpy (wtrow, var->data.F32[iy], Nx*sizeof(psF32));
+		memcpy (var->data.F32[iy], var->data.F32[Ny-1-iy], Nx*sizeof(psF32));
+		memcpy (var->data.F32[Ny-1-iy], wtrow, Nx*sizeof(psF32));
+	    }
+
+	    if (mask) {
+		memcpy (mkrow, mask->data.PS_TYPE_IMAGE_MASK_DATA[iy], Nx*sizeof(psImageMaskType));
+		memcpy (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy], mask->data.PS_TYPE_IMAGE_MASK_DATA[Ny-1-iy], Nx*sizeof(psImageMaskType));
+		memcpy (mask->data.PS_TYPE_IMAGE_MASK_DATA[Ny-1-iy], mkrow, Nx*sizeof(psImageMaskType));
+	    }
+	}
+    }
+    if ((xParity == -1) && (yParity == -1)) {
+	for (int iy = 0; iy < Ny/2; iy++) {
+	    for (int ix = 0; ix < Nx; ix++) {
+		imrow[Nx-1-ix] = image->data.F32[iy][ix];
+	    }
+	    for (int ix = 0; var && (ix < Nx); ix++) {
+		wtrow[Nx-1-ix] = var->data.F32[iy][ix];
+	    }
+	    for (int ix = 0; mask && (ix < Nx); ix++) {
+		mkrow[Nx-1-ix] = mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix];
+	    }
+
+	    for (int ix = 0; ix < Nx; ix++) {
+		image->data.F32[iy][Nx-1-ix] = image->data.F32[Ny-1-iy][ix];
+	    }
+	    for (int ix = 0; var && (ix < Nx); ix++) {
+		var->data.F32[iy][Nx-1-ix] = var->data.F32[Ny-1-iy][ix];
+	    }
+	    for (int ix = 0; mask && (ix < Nx); ix++) {
+		mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][Nx-1-ix] = mask->data.PS_TYPE_IMAGE_MASK_DATA[Ny-1-iy][ix];
+	    }
+
+	    memcpy (image->data.F32[Ny-1-iy], imrow, Nx*sizeof(psF32));
+	    if (var) memcpy (var->data.F32[Ny-1-iy], wtrow, Nx*sizeof(psF32));
+	    if (mask) memcpy (mask->data.PS_TYPE_IMAGE_MASK_DATA[Ny-1-iy], mkrow, Nx*sizeof(psImageMaskType));
+	}
+    }
+
+    // FIX_CONCEPT(cell->concepts, "CELL.XPARITY", S32, 1);
+    // FIX_CONCEPT(cell->concepts, "CELL.YPARITY", S32, 1);
+
+    psFree (imrow);
+    psFree (wtrow);
+    psFree (mkrow);
+    return true;
+}
