Index: trunk/pstamp/src/ppstampArguments.c
===================================================================
--- trunk/pstamp/src/ppstampArguments.c	(revision 34595)
+++ trunk/pstamp/src/ppstampArguments.c	(revision 34596)
@@ -25,6 +25,9 @@
     fprintf(stderr, "   [-mask   mk_image]    : mask image\n");
     fprintf(stderr, "   [-variance var_image] : variance image\n");
+    fprintf(stderr, "   [-sources sources]    : sources cmf (ignored for chip stage)\n");
     fprintf(stderr, "   [-stage stage]        : stage of input image (raw, chip, warp, stack, diff)\n");
     fprintf(stderr, "   [-write_jpeg]         : write a JPEG  format of the image stamp\n");
+    fprintf(stderr, "   [-write_cmf]          : create an output cmf with the sources overlapping the stamp\n");
+    fprintf(stderr, "   [-wholefile]          : ignore the region of interest and process the entire input image\n");
     // fprintf(stderr, "   [-no_censor_masked]   : do not set masked pixels to NAN\n");
     fprintf(stderr, "\n");
@@ -92,17 +95,39 @@
         options->stage = psStringCopy(argv[argnum]);
         psArgumentRemove(argnum, &argc, argv);
+    } else {
+        // Should we require this? 
+        options->stage = psStringCopy("unknown");
     }
     if ((argnum = psArgumentGet(argc, argv, "-write_jpeg"))) {
         psArgumentRemove(argnum, &argc, argv);
         options->writeJPEG = true;
-    } else {
-        options->writeJPEG = false;
+    }
+    if ((argnum = psArgumentGet(argc, argv, "-write_cmf"))) {
+        psArgumentRemove(argnum, &argc, argv);
+        options->writeCMF = true;
     }
 
-    pmConfigFileSetsMD(config->arguments, &argc, argv, "ASTROM", "-astrom", "-astromlist");
+    // XXX: Note: the various list options have never been tested with ppstamp to my knowledge
+    bool gotAstrom = false;
+    if ((argnum = psArgumentGet(argc, argv, "-astrom"))) {
+        gotAstrom = true;
+        pmConfigFileSetsMD(config->arguments, &argc, argv, "ASTROM", "-astrom", "-astromlist");
+    }
     pmConfigFileSetsMD(config->arguments, &argc, argv, "MASK",   "-mask", "-masklist");
     pmConfigFileSetsMD(config->arguments, &argc, argv, "VARIANCE", "-variance", "-variancelist");
 
-    // the input file is a required argument; if not found, we will exit
+    if ((argnum = psArgumentGet(argc, argv, "-sources"))) {
+        pmConfigFileSetsMD(config->arguments, &argc, argv, "SOURCES", "-sources", "-sourceslist");
+        // supplying a sources file implies that we want to save the output
+        options->writeCMF = true;
+    } else if (options->writeCMF && !gotAstrom) {
+        // if we didn't get a sources file but the user wanted us to write the sources we must
+        // have an astrometry file supplied
+        // XXX: Is this too restrictive? Could the sources be contained in say the input file?
+        psError(PSTAMP_ERR_ARGUMENTS, true, "cannot write cmf file unless input sources are supplied\n");
+        usage();
+    }
+
+    // the input image file is a required argument; if not found, we will exit
     bool status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
     if (!status) {
@@ -126,5 +151,5 @@
     }
 
-    // finally the output file
+    // finally the only argument left must be output outroot
     if (argc < 2) {
         psError(PSTAMP_ERR_ARGUMENTS, true, "must specify OUTPUT\n");
@@ -135,8 +160,5 @@
     }
 
-    // Add the output image (which remains on the command-line) to the arguments list
     psMetadataAddStr(config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "Name of the output image", argv[1]);
-
-    // psMetadataPrint(stdout, config->arguments,0);
 
     return config;
Index: trunk/pstamp/src/ppstampMakeStamp.c
===================================================================
--- trunk/pstamp/src/ppstampMakeStamp.c	(revision 34595)
+++ trunk/pstamp/src/ppstampMakeStamp.c	(revision 34596)
@@ -19,4 +19,5 @@
 static void chipToSky(pmAstromObj *pt, pmFPA *fpa, pmChip *chip);
 static bool setMaskedToNAN(pmConfig *config, psImage *image, psImage *mask, psImage *variance);
+static bool copySources(pmReadout *outputReadout, pmReadout *inputReadout, pmReadout *astromReadout, psRegion extractRegion);
 
 // convert the input chip's transforms to the output
@@ -80,19 +81,26 @@
 }
 
-static bool copyMetadata(pmFPAfile *output, pmFPAfile *input, pmChip *inChip, ppstampOptions *options, pmAstromObj *center)
+static bool copyMetadata(pmFPAfile *output, pmFPAfile *input, pmChip *inChip, ppstampOptions *options, pmAstromObj *center, pmFPAfile *astrom, pmFPAview *inView)
 {
     pmChip    *outChip;
-    pmFPAview *view = pmFPAviewAlloc(0);
+    pmFPAview *outView = pmFPAviewAlloc(0);
 
     // our output file has a single chip
-    view->chip = 0;
-    outChip = pmFPAviewThisChip(view, output->fpa);
-    psFree(view);
-
-    // copy data from the input chip header to the output.
+    outView->chip = 0;
+    outChip = pmFPAviewThisChip(outView, output->fpa);
+    psFree(outView);
+    pmHDU *outHDU = pmHDUGetHighest(output->fpa, outChip, NULL);
+
+    // copy data from the input's chip header to the output.
     // since some of the keywords might be duplicated we may not want to copy both
 
-    pmHDU *inHDU  = pmHDUFromChip(inChip);
-    pmHDU *outHDU = pmHDUGetHighest(output->fpa, outChip, NULL);
+    pmHDU *inHDU  = NULL;
+    if (strcmp(options->stage, "raw") && input != astrom) {
+        // Copy the header from the astrometry file since it contains the psphot and psastro results
+        pmChip *astromChip = pmFPAviewThisChip(inView, astrom->fpa);
+        inHDU  = pmHDUFromChip(astromChip);
+    } else {
+        inHDU  = pmHDUFromChip(inChip);
+    }
 
     if (inHDU->header) {
@@ -102,7 +110,10 @@
     }
 
-    // copy the fpa concepts
+    // copy the fpa and chip concepts
     pmConceptsCopyFPA(output->fpa, input->fpa, false, false);
+    // Needed to preserve FPA.ZP
     pmConceptsCopyChip(outChip, inChip, false);
+
+    // copy the cell concepts (needed to get CELL.EXPOSURE which gets used to set EXPTIME)
     pmCell *outCell = outChip->cells->data[0]; // The only output cell
 
@@ -122,5 +133,5 @@
     }
 
-    // If input had WCS convert it for stamp
+    // If input had WCS convert it for the new image coordinate system of our stamp
     if (input->fpa->toSky) {
         // copy the input fpa's transforms
@@ -135,9 +146,21 @@
         }
     } else {
-        psWarning("No WCS present in input\n");
-    }
-
+        psLogMsg("ppstampMakeStamp", PS_LOG_WARN, "No WCS present in input.");
+    }
+
+    // Save our specific metadata
     psMetadataAddF64(outHDU->header, PS_LIST_TAIL, "RA_DEG", PS_META_REPLACE, "Right Ascension of stamp center", RAD_TO_DEG(center->sky->r));
     psMetadataAddF64(outHDU->header, PS_LIST_TAIL, "DEC_DEG", PS_META_REPLACE, "Declination of stamp center", RAD_TO_DEG(center->sky->d));
+
+    // XXX: TODO: save the region of interest boundary and the offset to be applied. 
+    // XXX: Gene thinks that there may be a way to handle this in the WCS
+
+    // Now a few sanity checks
+    // Make sure zero point in the fpa concepts matches the observed value in the input header
+    bool status;
+    float zpt_obs = psMetadataLookupF32(&status, outHDU->header, "ZPT_OBS");
+    if (status) {
+        psMetadataAddF32(output->fpa->concepts, PS_LIST_TAIL, "FPA.ZP", PS_META_REPLACE, "Magnitude zero point", zpt_obs);
+    }
 
     ppstampVersionMetadata(outHDU->header, options);
@@ -324,7 +347,7 @@
 
             if (options->censorMasked && !setMaskedToNAN(config, outReadout->image, outReadout->mask, outReadout->variance)) {
-                 psError(PS_ERR_UNKNOWN, false, "failed to create postage stamp mask image\n");
-                 status = false;
-                 break;
+                psError(PS_ERR_UNKNOWN, false, "failed to create postage stamp mask image\n");
+                status = false;
+                break;
             }
         }
@@ -335,4 +358,16 @@
         status = true;
 
+        if (options->writeCMF) {
+            pmReadout *astromReadout = NULL;
+            if (astrom->fpa != input->fpa) {
+                astromReadout = pmFPAviewThisReadout(srcView, astrom->fpa);
+            }
+            if (!copySources(outReadout, astromReadout, astromReadout, extractRegion)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to extract sources from region of interest.\n");
+                status = false;
+                break;
+            }
+        }
+
         psFree(outReadout); // drop reference
     }
@@ -341,5 +376,6 @@
 
     if (status) {
-        status = copyMetadata(output, input, inChip, options, center);
+        // For raw stage we need to do more work to build a proper header
+        status = copyMetadata(output, input, inChip, options, center, astrom, view);
     }
     return status ? PS_EXIT_SUCCESS : PS_EXIT_UNKNOWN_ERROR;
@@ -428,11 +464,12 @@
     double dy = 0.5 * options->roip.dDEC / fpa->toSky->Ys;
 
-    if (dx > 5000) {
-        fprintf(stderr, "requested width %f too large reducing to 5000\n", dx);
-        dx = 5000;
-    }
-    if (dy > 5000) {
-        fprintf(stderr, "requested height %f too large reducing to 5000\n", dy);
-        dy = 5000;
+    // XXX: why do we limit this?
+    if (dx > 8000) {
+        psWarning( "requested width %f too large reducing to 8000\n", dx);
+        dx = 8000;
+    }
+    if (dy > 8000) {
+        psWarning( "requested height %f too large reducing to 8000\n", dy);
+        dy = 8000;
     }
 
@@ -480,6 +517,4 @@
     ppstampOverlap   returnval = PPSTAMP_OFF;
 
-//    fprintf(stderr, "ppstampChipBounds: %s\n", psRegionToString(*chipBounds));
-
     // set up the astrometry
     pmHDU *hdu = pmFPAviewThisHDU(view, astrom->fpa);
@@ -498,5 +533,4 @@
         }
     } else {
-        // we use a default FPA pixel scale of 1.0
         if (!pmAstromReadWCS (input->fpa, chip, hdu->header, 1.0) && mustHaveAstrometry) {
             psError(PS_ERR_UNKNOWN, false, "Unable to read WCS astrometry for input FPA.");
@@ -537,5 +571,7 @@
             center->chip->yErr = 0;
             onChip = true;
-            chipToSky(center, input->fpa, chip);
+            if (input->fpa->toSky) {
+                chipToSky(center, input->fpa, chip);
+            }
         }
     }
@@ -550,11 +586,11 @@
                 int width  = options->roip.dX;
                 int height = options->roip.dY;
-                if (width > 7000) {
-                    fprintf(stderr, "requested width %d too large reducing to 7000\n", width);
-                    width = 7000;
+                if (width > 8000) {
+                    psWarning( "requested width %d too large reducing to 8000\n", width);
+                    width = 8000;
                 }
-                if (height > 7000) {
-                    fprintf(stderr, "requested height %d too large reducing to 7000\n", height);
-                    height = 7000;
+                if (height > 8000) {
+                    psWarning( "requested height %d too large reducing to 8000\n", height);
+                    height = 8000;
                 }
 
@@ -675,5 +711,5 @@
 
     if (!foundOverlap && (returnval == PS_EXIT_SUCCESS)) {
-        fprintf(stderr, "ROI not found in input\n");
+        psWarning( "ROI not found in input\n");
         returnval = PSTAMP_NO_OVERLAP;
     }
@@ -739,7 +775,63 @@
     }
 
-    // XXX: this shouldn't be a fprintf
-    fprintf(stderr, "Censored %ld masked pixels\n", numCensored);
+    psLogMsg("ppstamp", PS_LOG_DETAIL, "Censored %ld masked pixels\n", numCensored);
 
     return true;
 }
+
+static bool copySources(pmReadout *outReadout, pmReadout *inReadout, pmReadout *astromReadout, psRegion extractRegion) {
+    bool status;
+
+    // first look for detections in the input readout. Those would have come from the -sources file
+    pmDetections *inDetections = psMetadataLookupPtr (&status, inReadout->analysis, "PSPHOT.DETECTIONS");
+    if (!inDetections) {
+        // No detections on the input readout. Try the astrometry readout if supplied.
+        if (astromReadout) {
+            inDetections = psMetadataLookupPtr (&status, astromReadout->analysis, "PSPHOT.DETECTIONS");
+            if (!inDetections) {
+                psLogMsg("ppstampMakeStamp", PS_LOG_WARN, "no detections found on input or astrometry readout\n");
+                return false;
+            } else {
+                psLogMsg("ppstampMakeStamp", PS_LOG_INFO, "using detections from astrom file\n");
+            }
+        } else {
+            psLogMsg("ppstampMakeStamp", PS_LOG_WARN, "no detections found on input readout\n");
+            return false;
+        }
+    }
+    if (!inDetections->allSources) {
+        psLogMsg("ppstampMakeStamp", PS_LOG_WARN, "no sources array found on detections structure\n");
+        return false;
+    }
+
+    // Ok we have sources, allocate a detections structure and copy them to the output readout
+    psArray *inSources = inDetections->allSources;
+
+    pmDetections *outDetections = pmDetectionsAlloc();
+    psMetadataAddPtr (outReadout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN,
+        "psphot detections", outDetections);
+
+    psArray *outSources = outDetections->allSources = psArrayAllocEmpty( 100 );
+
+    // include sources that are off the stamp by just a little bit
+    #define EXPAND_SIZE 16
+    psRegion sourceRegion = extractRegion;
+    sourceRegion.x0 -= EXPAND_SIZE;
+    sourceRegion.y0 -= EXPAND_SIZE;
+    sourceRegion.x1 += EXPAND_SIZE;
+    sourceRegion.y1 += EXPAND_SIZE;
+
+    for (int i = 0; i < inSources->n; i++ ) {
+        pmSource *src = inSources->data[i];
+
+        float x = src->peak->xf;
+        float y = src->peak->yf;
+        if (x < sourceRegion.x0 || x > sourceRegion.x1 ||
+            y < sourceRegion.y0 || y > sourceRegion.y1) {
+            continue;
+        }
+        psArrayAdd(outSources, 100, src);
+    }
+
+    return true;
+}
Index: trunk/pstamp/src/ppstampOptions.c
===================================================================
--- trunk/pstamp/src/ppstampOptions.c	(revision 34595)
+++ trunk/pstamp/src/ppstampOptions.c	(revision 34596)
@@ -32,4 +32,5 @@
     options->censorMasked = false;
     options->writeJPEG = false;
+    options->writeCMF = false;
     options->nocompress = false;
     options->wholeFile = false;
Index: trunk/pstamp/src/ppstampOptions.h
===================================================================
--- trunk/pstamp/src/ppstampOptions.h	(revision 34595)
+++ trunk/pstamp/src/ppstampOptions.h	(revision 34596)
@@ -14,4 +14,5 @@
     bool        censorMasked;
     bool        writeJPEG;
+    bool        writeCMF;
     bool        nocompress;
     //
Index: trunk/pstamp/src/ppstampParseCamera.c
===================================================================
--- trunk/pstamp/src/ppstampParseCamera.c	(revision 34595)
+++ trunk/pstamp/src/ppstampParseCamera.c	(revision 34596)
@@ -120,4 +120,34 @@
     }
 
+    // Set up the input and output sources files if needed
+    if (options->writeCMF) {
+        bool status;
+
+        // see if -sources file was supplied. 
+        // If so define the file.
+        psPtr sourcesFile = psMetadataLookupStr(&status, config->arguments, "SOURCES");
+        if (sourcesFile) {
+            pmFPAfile *sources = pmFPAfileBindFromArgs(&status, input, config, "PPSTAMP.INPUT.SOURCES", "SOURCES");
+            if (!status) {
+                psError(psErrorCodeLast(), false, "Failed to load file definition for PPSTAMP.INPUT.SOURCES");
+                return false;
+            }
+            if (!sources && !astrom) {
+                psError(psErrorCodeLast(), false, "Failed to define input sources file");
+                return false;
+            }
+        } else {
+            psLogMsg ("ppstamp", PS_LOG_INFO, "output sources file requested but no input supplied. Will try the supplied astrometry file.\n");
+        }
+        
+        pmFPAfile *outputSources = NULL;
+        outputSources = pmFPAfileDefineSkycell(config, output->fpa, "PPSTAMP.OUTPUT.SOURCES");
+        if (!outputSources) {
+            psError(psErrorCodeLast(), false, "Failed to define output sources file");
+            return false;
+        }
+        outputSources->save = true;
+    }
+
     pmFPAfile *chipImage = pmFPAfileDefineChipMosaic(config, input->fpa, "PPSTAMP.CHIP");
     if (!chipImage) {
Index: trunk/pstamp/src/pstamp.h
===================================================================
--- trunk/pstamp/src/pstamp.h	(revision 34595)
+++ trunk/pstamp/src/pstamp.h	(revision 34596)
@@ -26,15 +26,24 @@
 
 // values for options mask.
-#define PSTAMP_SELECT_IMAGE      1
-#define PSTAMP_SELECT_MASK       2
-#define PSTAMP_SELECT_WEIGHT     4
-#define PSTAMP_SELECT_CMF        8
-#define PSTAMP_SELECT_PSF       16
-#define PSTAMP_SELECT_BACKMDL   32
-#define PSTAMP_SELECT_INVERSE 1024
-#define PSTAMP_SELECT_UNCONV  2048
-#define PSTAMP_USE_IMFILE_ID 16384
+#define PSTAMP_SELECT_IMAGE         1
+#define PSTAMP_SELECT_MASK          2
+#define PSTAMP_SELECT_WEIGHT        4
+#define PSTAMP_SELECT_SOURCES       8
+#define PSTAMP_SELECT_CMF           8
+#define PSTAMP_SELECT_PSF           16
+#define PSTAMP_SELECT_BACKMDL       32
+#define PSTAMP_SELECT_JPEG          64
+// unused                           128
+// unused                           256
+#define PSTAMP_SELECT_UNCOMPRESSED  512
+#define PSTAMP_SELECT_INVERSE       1024
+#define PSTAMP_SELECT_UNCONV        2048
+#define PSTAMP_RESTORE_BACKGROUND   4096
+// unused                           8192
+#define PSTAMP_USE_IMFILE_ID        16384
 
-#define PSTAMP_NO_WAIT_FOR_UPDATE 32768
+#define PSTAMP_NO_WAIT_FOR_UPDATE   32768
+#define PSTAMP_REQUEST_UNCENSORED  0x10000
+#define PSTAMP_REQUIRE_UNCENSORED  0x20000
 
 #define PSTAMP_CENTER_IN_PIXELS 1
