Index: trunk/psModules/src/camera/pmFPACopy.c
===================================================================
--- trunk/psModules/src/camera/pmFPACopy.c	(revision 15140)
+++ trunk/psModules/src/camera/pmFPACopy.c	(revision 15180)
@@ -83,4 +83,9 @@
     assert(source);
     assert(xBin > 0 && yBin > 0);
+
+    if (!source->data_exists) {
+        // Copied everything that exists
+        return true;
+    }
 
     // XXX this is a programming / config error
@@ -347,4 +352,9 @@
     assert(yBin > 0);
 
+    if (!source->data_exists) {
+        // Copied everything that exists
+        return true;
+    }
+
     psArray *targetCells = target->cells; // The target cells
     psArray *sourceCells = source->cells; // The source cells
Index: trunk/psModules/src/camera/pmFPAfile.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.c	(revision 15140)
+++ trunk/psModules/src/camera/pmFPAfile.c	(revision 15180)
@@ -40,4 +40,5 @@
         psFitsClose (file->fits);
     }
+    psFree(file->compression);
 
     psFree (file->filerule);
@@ -72,4 +73,6 @@
     file->fpa = NULL;
     file->fits = NULL;
+    file->compression = NULL;
+    file->bitpix = 0;
     file->names = psMetadataAlloc();
 
Index: trunk/psModules/src/camera/pmFPAfile.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.h	(revision 15140)
+++ trunk/psModules/src/camera/pmFPAfile.h	(revision 15180)
@@ -4,6 +4,6 @@
  * @author EAM, IfA
  *
- * @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-09-19 21:37:58 $
+ * @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-10-03 21:32:43 $
  * Copyright 2004-2005 Institute for Astronomy, University of Hawaii
  */
@@ -51,6 +51,5 @@
 } pmFPAfileState;
 
-typedef struct
-{
+typedef struct {
     pmFPAfileMode mode;                 // is this file read, written, or only used internally?
     pmFPAfileType type;                 // what type of data is read from / written to disk?
@@ -63,5 +62,7 @@
 
     pmFPA *fpa;                         // for I/O files, we carry a pointer to the complete fpa
-    psFits *fits;                       // for I/O files of fits type (IMAGE, CMP, CMF), we carry a file handle
+    psFits *fits;                       // for I/O files of fits type (IMAGE, CMP, CMF) we carry a file handle
+    psFitsCompression *compression;     // Compression for FITS images
+    int bitpix;                         // Bits per pixel for output
 
     bool wrote_phu;                     // have we written a PHU for this file?
@@ -93,6 +94,5 @@
     psMetadata *format;                 // Camera format
     psString formatName;                // name of the camera format
-}
-pmFPAfile;
+} pmFPAfile;
 
 // allocate an empty pmFPAfile structure
Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 15140)
+++ trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 15180)
@@ -8,4 +8,5 @@
 #include <pslib.h>
 
+#include "pmErrorCodes.h"
 #include "pmConfig.h"
 #include "pmDetrendDB.h"
@@ -19,4 +20,79 @@
 #include "pmFPAConstruct.h"
 
+
+// Get the file rule of interest
+// Look up the name of the set of file rules to use, get that set from the site configuration, and return the
+// appropriate rule from the set.
+static psMetadata *getFileRule(const pmConfig *config, // Configuration
+                               const psMetadata *camera, // Camera configuration of interest
+                               const char *name // Name of rule to read
+    )
+{
+    assert(config);
+    assert(config->site);
+
+    psMetadataItem *item = psMetadataLookup(camera, "FILERULES"); // Item with the file rule of interest
+    if (!item) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find FILERULES in the camera configuration.");
+        return NULL;
+    }
+
+    psMetadata *filerules = NULL;       // File rules from the site configuration
+    switch (item->type) {
+      case PS_DATA_METADATA:
+        // It's what we're after
+        filerules = item->data.md;
+        break;
+      case PS_DATA_STRING: {
+          // It's the name of a file --- read the file, and store it for future use
+          if (!pmConfigFileRead(&filerules, item->data.str, "filerules")) {
+              psError(PM_ERR_CONFIG, false, "Trouble reading reading file rules from %s  --- "
+                      "ignored.\n", item->data.str);
+              psFree(filerules);
+              return NULL;
+          }
+
+          // Muck around under the hood to replace the filename with the metadata; don't try this at home,
+          // kids
+          item->type = PS_DATA_METADATA;
+          psFree(item->data.str);
+          item->data.md = filerules;
+          break;
+      }
+      default:
+        psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                "Unexpected type for %s (%x) in FILERULES in SITE configuration.",
+                name, item->type);
+        return NULL;
+    }
+
+    // select the name from the FILERULES
+    // check for alias name (type == STR, name is aliased name)
+    bool mdok;                          // Status of MD lookup
+    const char *realname = psMetadataLookupStr(&mdok, filerules, name); // Name of file rule to look up
+    if (!realname || strlen(realname) == 0) {
+        realname = name;
+    }
+
+    return psMetadataLookupMetadata(NULL, filerules, realname);
+}
+
+// Parse an option from a metadata, returning the appropriate integer value
+static int parseOptionInt(const psMetadata *md, // Metadata containing the option
+                          const char *name, // Option name
+                          const char *source, // Description of source, for warning messages
+                          int defaultValue // Default value
+                          )
+{
+    psMetadataItem *item = psMetadataLookup(md, name); // Item with the value of interest
+    if (!item) {
+        psWarning("Unable to find value for %s in %s --- set to %d.", name, source, defaultValue);
+        return defaultValue;
+    }
+    int value = psMetadataItemParseS32(item); // Value of interst
+    return value;
+}
+
+
 // define an input-type pmFPAfile, bind to the optional fpa if supplied
 pmFPAfile *pmFPAfileDefineInput(const pmConfig *config, pmFPA *fpa, const char *name)
@@ -30,20 +106,7 @@
     char *type;
 
-    // select the FILERULES from config->camera
-    psMetadata *filerules = psMetadataLookupPtr (&status, config->camera, "FILERULES");
-    if (filerules == NULL) {
-        psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
-        return NULL;
-    }
-
-    // select the name from the FILERULES
-    // check for alias name (type == STR, name is aliased name)
-    const char *realname = psMetadataLookupStr (&status, filerules, name);
-    if (!realname || strlen(realname) == 0) {
-        realname = name;
-    }
-
-    psMetadata *data = psMetadataLookupPtr (&status, filerules, realname);
-    if (data == NULL) {
+    const psMetadata *camera = (fpa ? fpa->camera : config->camera); // Camera configuration for this file
+    psMetadata *data = getFileRule(config, camera, name); // File rule
+    if (!data) {
         psError(PS_ERR_IO, true, "Can't find file rule %s!", name);
         return NULL;
@@ -76,7 +139,10 @@
     file->freeLevel = file->dataLevel;
 
-    if (fpa != NULL) {
+    if (fpa) {
         file->fpa = psMemIncrRefCounter(fpa);
         file->camera = psMemIncrRefCounter((psMetadata *)fpa->camera);
+        file->cameraName = psMemIncrRefCounter(config->cameraName); // XXX Is this the correct thing to do?
+    } else {
+        file->camera = psMemIncrRefCounter(config->camera);
         file->cameraName = psMemIncrRefCounter(config->cameraName);
     }
@@ -103,42 +169,4 @@
 {
     bool status;
-
-    // select the FILERULES from the camera config
-    psMetadata *filerules = psMetadataLookupPtr(&status, config->camera, "FILERULES");
-    if (filerules == NULL) {
-        psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
-        return NULL;
-    }
-
-    // select the name from the FILERULES
-    // check for alias name (type == STR, name is aliased name)
-    const char *realname = psMetadataLookupStr(&status, filerules, name);
-    if (!realname || strlen(realname) == 0) {
-        realname = name;
-    }
-
-    psMetadata *data = psMetadataLookupPtr (&status, filerules, realname);
-    if (data == NULL) {
-        psError(PS_ERR_IO, true, "Can't find file rule %s!", name);
-        return NULL;
-    }
-
-    pmFPAfile *file = pmFPAfileAlloc();
-
-    // save the name of this pmFPAfile
-    file->name = psStringCopy(name);
-
-    file->filerule = psMemIncrRefCounter(psMetadataLookupStr(&status, data, "FILENAME.RULE"));
-
-    const char *type = psMetadataLookupStr(&status, data, "FILE.TYPE");
-    file->type = pmFPAfileTypeFromString(type);
-    if (file->type == PM_FPA_FILE_NONE) {
-        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
-        psFree(file);
-        return NULL;
-    }
-
-    file->mode = PM_FPA_MODE_WRITE;
-    file->save = false;
 
     // Use the camera we were told to, the camera of the provided FPA, or default to the default camera
@@ -169,4 +197,56 @@
         }
     }
+
+    psMetadata *data = getFileRule(config, camera, name); // File rule
+    if (!data) {
+        psError(PS_ERR_IO, true, "Can't find file rule %s!", name);
+        return NULL;
+    }
+
+    pmFPAfile *file = pmFPAfileAlloc();
+
+    // save the name of this pmFPAfile
+    file->name = psStringCopy(name);
+
+    file->filerule = psMemIncrRefCounter(psMetadataLookupStr(&status, data, "FILENAME.RULE"));
+
+    const char *type = psMetadataLookupStr(&status, data, "FILE.TYPE");
+    file->type = pmFPAfileTypeFromString(type);
+    if (file->type == PM_FPA_FILE_NONE) {
+        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
+        psFree(file);
+        return NULL;
+    }
+
+    file->mode = PM_FPA_MODE_WRITE;
+    file->save = false;
+
+    // Use the camera we were told to, the camera of the provided FPA, or default to the default camera
+    psMetadata *camera;                 // Camera configuration
+    if (!cameraName || strlen(cameraName) == 0) {
+        if (fpa && fpa->camera) {
+            camera = (psMetadata*)fpa->camera; // Casting away const, so I can put it in the file
+        } else {
+            camera = config->camera;
+            cameraName = config->cameraName;
+        }
+    } else {
+        bool mdok;                      // Status of MD lookup
+        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS"); // Known cameras
+        if (!mdok || !cameras) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
+            return NULL;
+        }
+        camera = psMetadataLookupMetadata(&mdok, cameras, cameraName); // Camera configuration of interest
+        if (!mdok || !camera) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find automatically generated "
+                    "camera configuration %s in site configuration.\n", cameraName);
+            return NULL;
+        }
+
+        if (fpa && fpa->camera && fpa->camera != camera) {
+            psAbort("Camera of bound FPA is not the requested camera --- there is an inconsistency!");
+        }
+    }
     file->camera = psMemIncrRefCounter(camera);
     file->cameraName = psMemIncrRefCounter(cameraName);
@@ -175,10 +255,10 @@
     # if (0)
     if (cameraName) {
-	if (!strcmp(cameraName + strlen(cameraName) - 5, "-CHIP")) {
-	    file->mosaicLevel = PM_FPA_LEVEL_CHIP;
-	}
-	if (!strcmp(cameraName + strlen(cameraName) - 5, "-FPA")) {
-	    file->mosaicLevel = PM_FPA_LEVEL_FPA;
-	}
+        if (!strcmp(cameraName + strlen(cameraName) - 5, "-CHIP")) {
+            file->mosaicLevel = PM_FPA_LEVEL_CHIP;
+        }
+        if (!strcmp(cameraName + strlen(cameraName) - 5, "-FPA")) {
+            file->mosaicLevel = PM_FPA_LEVEL_FPA;
+        }
     }
     # endif
@@ -209,4 +289,42 @@
         file->fpa = pmFPAConstruct(file->camera);
     }
+
+    // Get FITS output scheme
+    const char *fitsType = psMetadataLookupStr(&status, data, "FITS.TYPE"); // Name of FITS scheme to use
+    if (fitsType && strcasecmp(fitsType, "NONE") != 0) {
+        psMetadata *fitsTypes = psMetadataLookupMetadata(&status, camera, "FITS"); // The FITS schemes
+        if (!fitsTypes) {
+            psWarning("Unable to find FITS in camera configuration --- compression disabled.");
+            goto COMPRESSION_DONE;
+        }
+        psMetadata *scheme = psMetadataLookupMetadata(NULL, fitsTypes, fitsType); // FITS scheme
+        if (!scheme) {
+            psWarning("Unable to find %s in FITS in camera configuration --- compression disabled.",
+                      fitsType);
+            goto COMPRESSION_DONE;
+        }
+        const char *typeString = psMetadataLookupStr(NULL, scheme, "COMPRESSION"); // Compression type
+        if (!typeString || strlen(typeString) == 0) {
+            psWarning("Can't find COMPRESSION in FITS scheme %s --- compression disabled.", fitsType);
+            goto COMPRESSION_DONE;
+        }
+        psFitsCompressionType type = psFitsCompressionTypeFromString(typeString); // Compression type enum
+
+        psString source = NULL;         // Source of options
+        psStringAppend(&source, "%s in FITS in camera %s", fitsType, cameraName);
+        psVector *tile = psVectorAlloc(3, PS_TYPE_S32); // Tile sizes
+        file->bitpix = parseOptionInt(scheme, "BITPIX", source, 0); // Bits per pixel
+        tile->data.S32[0] = parseOptionInt(scheme, "TILE.X", source, 0); // Tiling in x
+        tile->data.S32[1] = parseOptionInt(scheme, "TILE.Y", source, 1); // Tiling in y
+        tile->data.S32[2] = parseOptionInt(scheme, "TILE.Z", source, 1); // Tiling in z
+        int noise = parseOptionInt(scheme, "NOISE", source, 16); // Noise bits
+        int hscale = parseOptionInt(scheme, "HSCALE", source, 0); // Scaling for HCOMPRESS
+        int hsmooth = parseOptionInt(scheme, "HSMOOTH", source, 0); // Smoothing for HCOMPRESS
+        psFree(source);
+
+        file->compression = psFitsCompressionAlloc(type, tile, noise, hscale, hsmooth);
+        psFree(tile);
+    }
+COMPRESSION_DONE:
 
     file->fileLevel = pmFPAPHULevel(format);
Index: trunk/psModules/src/camera/pmFPAfileFitsIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 15140)
+++ trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 15180)
@@ -471,24 +471,30 @@
     if (file->wrote_phu) return true;
 
-    // select or generate the desired fpa in the correct output format 
+    // select or generate the desired fpa in the correct output format
     pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config);
+    pmHDU *phu = pmFPAviewThisHDU(view, fpa);
+    if (!phu || !phu->blankPHU) {
+        // No PHU to write!
+        psFree(fpa);
+        return true;
+    }
 
     switch (file->fileLevel) {
       case PM_FPA_LEVEL_FPA:
-	status = pmFPAWrite(fpa, file->fits, NULL, true, false);
-	break;
+        status = pmFPAWrite(fpa, file->fits, NULL, true, false);
+        break;
       case PM_FPA_LEVEL_CHIP: {
-	  pmChip *chip = pmFPAviewThisChip(view, fpa);
-	  status = pmChipWrite(chip, file->fits, NULL, true, false);
-	  break;
+          pmChip *chip = pmFPAviewThisChip(view, fpa);
+          status = pmChipWrite(chip, file->fits, NULL, true, false);
+          break;
       }
       case PM_FPA_LEVEL_CELL: {
-	  pmCell *cell = pmFPAviewThisCell(view, fpa);
-	  status = pmCellWrite(cell, file->fits, NULL, true);
-	  break;
+          pmCell *cell = pmFPAviewThisCell(view, fpa);
+          status = pmCellWrite(cell, file->fits, NULL, true);
+          break;
       }
       default:
-	psAbort("fileLevel not correctly set");
-	break;
+        psAbort("fileLevel not correctly set");
+        break;
     }
 
Index: trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.c	(revision 15140)
+++ trunk/psModules/src/camera/pmFPAfileIO.c	(revision 15180)
@@ -359,11 +359,19 @@
             return false;
         }
+
+        // do we need to write out a PHU?
+        if (!pmFPAfileWritePHU(file, fileView, config)) {
+            psError(PS_ERR_IO, false, "failed to write phu for %s (%s)", file->filename, file->name);
+            return false;
+        }
+
         psFree (fileView);
     }
 
-    // do we need to write out a PHU?
-    if (level >= file->fileLevel) {
-        if (!pmFPAfileWritePHU (file, view, config)) {
-            psError(PS_ERR_IO, false, "failed to write phu for %s (%s)", file->filename, file->name);
+    if (file->compression) {
+        psTrace("psModules.camera", 7, "Setting compression for %s (%s)\n", file->filename, file->name);
+        if (!psFitsCompressionApply(file->fits, file->compression)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to set compression options for %s (%s) (%d:%d:%d)\n",
+                    file->filename, file->name, view->chip, view->cell, view->readout);
             return false;
         }
@@ -667,5 +675,6 @@
       case PM_FPA_FILE_CMF:
       case PM_FPA_FILE_PSF:
-        psTrace ("psModules.camera", 5, "opening %s (%s) (%d:%d:%d)\n", file->filename, file->name, view->chip, view->cell, view->readout);
+        psTrace ("psModules.camera", 5, "opening %s (%s) (%d:%d:%d)\n",
+                 file->filename, file->name, view->chip, view->cell, view->readout);
         file->fits = psFitsOpen (file->filename, mode);
         if (file->fits == NULL) {
@@ -679,5 +688,6 @@
             psMetadata *fileMenu = psMetadataLookupMetadata (NULL, file->format, "FILE");
             if (!fileMenu) {
-                psError (PS_ERR_IO, true, "FILE METADATA missing from camera format %s\n", file->formatName);
+                psError (PS_ERR_IO, true, "FILE METADATA missing from camera format %s\n",
+                         config->formatName);
                 return false;
             }
@@ -688,8 +698,18 @@
         }
 
-        // In some cases, we need to read the PHU after we've opened the file.  This happens for
-        // the images supplied by the detrend database, which are only identified here (pmConfigConvertFilename).
+        if (file->compression) {
+            psTrace("psModules.camera", 7, "Setting compression for %s (%s)\n", file->filename, file->name);
+            if (!psFitsCompressionApply(file->fits, file->compression)) {
+                psError(PS_ERR_UNKNOWN, false, "Unable to set compression options for %s (%s) (%d:%d:%d)\n",
+                        file->filename, file->name, view->chip, view->cell, view->readout);
+                return false;
+            }
+        }
+
+        // In some cases, we need to read the PHU after we've opened the file.  This happens for the images
+        // supplied by the detrend database, which are only identified here (pmConfigConvertFilename).
         if (!pmFPAfileReadPHU (file, view, config)) {
-            psError (PS_ERR_IO, true, "error reading PHU for %s (%s) (%d:%d:%d)\n", file->filename, file->name, view->chip, view->cell, view->readout);
+            psError (PS_ERR_IO, true, "error reading PHU for %s (%s) (%d:%d:%d)\n",
+                     file->filename, file->name, view->chip, view->cell, view->readout);
             return false;
         }
@@ -758,5 +778,5 @@
             return false;
         }
-	file->formatName = psStringCopy(config->formatName);
+        file->formatName = psStringCopy(config->formatName);
 
     } else {
@@ -796,12 +816,12 @@
       case PM_FPA_FILE_WEIGHT:
       case PM_FPA_FILE_FRINGE:
-	status = pmFPAviewFitsWritePHU (view, file, config);
-	break;
+        status = pmFPAviewFitsWritePHU (view, file, config);
+        break;
       case PM_FPA_FILE_CMF:
-	status = pmSource_CMF_WritePHU (view, file, config);
-	break;
+        status = pmSource_CMF_WritePHU (view, file, config);
+        break;
       case PM_FPA_FILE_PSF:
-	status = pmPSFmodelWritePHU (view, file, config);
-	break;
+        status = pmPSFmodelWritePHU (view, file, config);
+        break;
       case PM_FPA_FILE_SX:
       case PM_FPA_FILE_RAW:
