IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jan 26, 2009, 8:40:07 PM (17 years ago)
Author:
eugene
Message:

incorporating changes from 16bit mask upgrades (eam_branch_20081230)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/config/pmConfigMask.c

    r19870 r21183  
    99#include "pmConfigMask.h"
    1010
    11 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    12 // Private functions
    13 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    14 
    15 // maskSetValues examine named mask values and set the bits for maskValue and markValue.
    16 // Ensures that the below-named bad mask values are set, and calculates the mask value to catch them all
    17 // Ensure that the below-named other mask values are set (to 0x00 if necessary)
    18 
    19 // List of mask names for "bad" (i.e., mask me please) pixels
    20 static const char *badMaskNames[] = { "DETECTOR", // Something is wrong with the detector
    21                                       "DARK", // Pixel doesn't dark-subtract properly
    22                                       "FLAT", // Pixel doesn't flat-field properly
    23                                       "BLANK", // Pixel doesn't contain valid data
    24                                       "RANGE",// Pixel is out-of-range of linearity
    25                                       "SAT",  // Pixel is saturated
    26                                       // "LOW",  // Pixel is low
    27                                       // "CONV", // Pixel is bad after convolution with a bad pixel
    28                                       "BAD", // Pixel is low
    29                                       "BAD.WARP", // Pixel is bad after convolution with a bad pixel
    30                                       "CR",   // Pixel contains a cosmic ray
    31                                       "GHOST",// Pixel contains an optical ghost
    32                                       NULL // End marker
     11static pmConfigMaskInfo masks[] = {
     12    { "DETECTOR",  NULL,       0x00, true  },   // Something is wrong with the detector
     13    { "DARK",      "DETECTOR", 0x00, true  },   // Pixel doesn't dark-subtract properly
     14    { "FLAT",      "DETECTOR", 0x01, true  },   // Pixel doesn't flat-field properly
     15    { "BLANK",     "DETECTOR", 0x01, true  },   // Pixel doesn't contain valid data
     16    { "RANGE",     NULL,       0x00, true  },   // Pixel is out-of-range of linearity
     17    { "SAT",       "RANGE",    0x01, true  },   // Pixel is saturated
     18    { "BAD",       "RANGE",    0x01, true  },   // Pixel is low
     19    { "BAD.WARP",  NULL,       0x01, true  },   // Pixel is bad after convolution with a bad pixel
     20    { "CR",        NULL,       0x00, true  },   // Pixel contains a cosmic ray
     21    { "GHOST",     NULL,       0x00, true  },   // Pixel contains an optical ghost
     22    { "POOR.WARP", NULL,       0x00, false },   // Pixel is poor after convolution with a bad pixel
     23    // "LOW"  Pixel is low
     24    // "CONV" Pixel is bad after convolution with a bad pixel
    3325};
    34 // Fallback names in case a bad mask name is not defined
    35 static const char *fallbackMaskNames[] = { NULL, // DETECTOR
    36                                            "DETECTOR", // DARK
    37                                            "DETECTOR", // FLAT
    38                                            "DETECTOR", // BLANK
    39                                            NULL, // RANGE
    40                                            "RANGE", // SAT
    41                                            "RANGE", // LOW
    42                                            NULL, // CONV
    43                                            NULL, // CR
    44                                            NULL, // GHOST
    45 };
    46 // Default values in case a bad mask name and its fallback is not defined
    47 static const psMaskType defaultMask[] = { 0x00, // DETECTOR
    48                                           0x00, // DARK
    49                                           0x01, // FLAT
    50                                           0x01, // BLANK
    51                                           0x00, // RANGE
    52                                           0x01, // SAT
    53                                           0x01, // LOW
    54                                           0x01, // CONV
    55                                           0x00, // CR
    56                                           0x00  // GHOST
    57 };
    58 // Other mask names to ensure exist; these shouldn't be combined in the MASK.VALUE
    59 static const char *otherMaskNames[] = { // "POOR", // Pixel is poor after convolution with a bad pixel
    60                                         "POOR.WARP", // Pixel is poor after convolution with a bad pixel
    61                                         NULL // End marker
    62 };
    63 
    64 static bool maskSetValues(psMaskType *outMaskValue, // Value of MASK.VALUE, returned
    65                           psMaskType *outMarkValue, // Value of MARK.VALUE, returned
    66                           psMetadata *source  // Source of mask bits
    67                           )
     26
     27// The functions in this file do not force the recipe or header values to be stored as the same
     28// type as psImageMaskType : they only check that the given values will fit in the space
     29// provided by psImageMaskType.  This should allow some backwards compatibility (old 8-bit
     30// masks will work with a 16-bit system), but will catch unhandled conflicts (trying to fit 16
     31// bits in 8-bits of space).
     32
     33// XXX this file does not have psError vs psWarning worked out correctly.  some of the
     34// failure modes should result in errors, not just warnings.
     35
     36// pmConfigMaskSetInMetadata examines named mask values and set the bits for maskValue and
     37// markValue.  Ensures that the below-named mask values are set, and calculates the mask value
     38// to catch all of the mask values marked as 'bad'.  Supplies the fallback name if the primary
     39// name is not found, or the default values if the fallback name is not found.
     40
     41bool pmConfigMaskSetInMetadata(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned
     42                               psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned
     43                               psMetadata *source  // Source of mask bits
     44    )
    6845{
    6946    PS_ASSERT_METADATA_NON_NULL(source, false);
    70 
     47   
    7148    // Ensure all the bad mask names exist, and set the value to catch all bad pixels
    72     psMaskType maskValue = 0;           // Value to mask to catch all the bad pixels
    73     for (int i = 0; badMaskNames[i]; i++) {
    74         const char *name = badMaskNames[i]; // Name for mask
    75         const char *fallback = fallbackMaskNames[i]; // Fallback for mask
    76 
     49    psImageMaskType maskValue = 0;           // Value to mask to catch all the bad pixels
     50    psImageMaskType allMasks = 0;            // Value to mask to catch all masked bits (to set MARK)
     51
     52    int nMasks = sizeof (masks) / sizeof (pmConfigMaskInfo);
     53
     54    for (int i = 0; i < nMasks; i++) {
    7755        bool mdok;                      // Status of MD lookup
    78         psMaskType value = psMetadataLookupU8(&mdok, source, name); // Value of mask
     56        psImageMaskType value = psMetadataLookupImageMaskFromGeneric(&mdok, source, masks[i].badMaskName); // Value of mask
     57        if (!mdok) {
     58            psWarning ("problem with mask value %s\n", masks[i].badMaskName);
     59        }
     60
    7961        if (!value) {
    80             if (fallback) {
    81                 value = psMetadataLookupU8(&mdok, source, fallback);
    82             }
    83             if (!value) {
    84                 value = defaultMask[i];
    85             }
    86             psMetadataAddU8(source, PS_LIST_TAIL, name, PS_META_REPLACE, NULL, value);
    87         }
    88         maskValue |= value;
    89     }
    90 
    91     // Ensure all the other mask names exist
    92     for (int i = 0; otherMaskNames[i]; i++) {
    93         const char *name = otherMaskNames[i]; // Name for mask
    94         bool mdok;                      // Status of MD lookup
    95         psMaskType value = psMetadataLookupU8(&mdok, source, name); // Value of mask
    96         if (!value) {
    97             psMetadataAddU8(source, PS_LIST_TAIL, name, PS_META_REPLACE, NULL, 0x00);
    98         }
     62            if (masks[i].fallbackName) {
     63                value = psMetadataLookupImageMaskFromGeneric(&mdok, source, masks[i].fallbackName);
     64            }
     65            if (!value) {
     66                value = masks[i].defaultMaskValue;
     67            }
     68            psMetadataAddImageMask(source, PS_LIST_TAIL, masks[i].badMaskName, PS_META_REPLACE, NULL, value);
     69        }
     70        if (masks[i].isBad) {
     71            maskValue |= value;
     72        }
     73        allMasks |= value;
    9974    }
    10075
    10176    // search for an unset bit to use for MARK:
    102     psMaskType markValue = 0x80;
    103 
    104     int nBits = sizeof(psMaskType) * 8;
     77    psImageMaskType markValue = 0x00;
     78    psImageMaskType markTrial = 0x01;
     79
     80    int nBits = sizeof(psImageMaskType) * 8;
    10581    for (int i = 0; !markValue && (i < nBits); i++) {
    106         if (maskValue & markValue) {
    107             markValue >>= 1;
     82        if (allMasks & markTrial) {
     83            markTrial <<= 1;
    10884        } else {
    109             markValue = markValue;
     85            markValue = markTrial;
    11086        }
    11187    }
     
    11692
    11793    // update the list with the results
    118     psMetadataAddU8(source, PS_LIST_TAIL, "MASK.VALUE", PS_META_REPLACE, NULL, maskValue);
    119     psMetadataAddU8(source, PS_LIST_TAIL, "MARK.VALUE", PS_META_REPLACE, NULL, markValue);
     94    psMetadataAddImageMask(source, PS_LIST_TAIL, "MASK.VALUE", PS_META_REPLACE, NULL, maskValue);
     95    psMetadataAddImageMask(source, PS_LIST_TAIL, "MARK.VALUE", PS_META_REPLACE, NULL, markValue);
    12096
    12197    if (outMaskValue) {
     
    130106
    131107// Get a mask value by name(s)
    132 static psMaskType maskGet(psMetadata *source, // Source of masks
    133                           const char *masks // Mask values to get
    134                           )
    135 {
    136     psMaskType mask = 0;                // Mask value, to return
     108psImageMaskType pmConfigMaskGetFromMetadata(psMetadata *source, // Source of masks
     109                                            const char *masks // Mask values to get
     110    )
     111{
     112    psImageMaskType mask = 0;                // Mask value, to return
    137113
    138114    psArray *names = psStringSplitArray(masks, " ,;", false); // Array of symbolic names
     
    140116        const char *name = names->data[i]; // Symbolic name of interest
    141117        bool mdok;                      // Status of MD lookup
    142         psMaskType value = psMetadataLookupU8(&mdok, source, name);
     118        psImageMaskType value = psMetadataLookupImageMaskFromGeneric(&mdok, source, name);
    143119        if (!mdok) {
    144120            // Try and generate the value if we can
    145121            if (strcmp(name, "MASK.VALUE") == 0 || strcmp(name, "MARK.VALUE") == 0) {
    146                 if (!maskSetValues(NULL, NULL, source)) {
     122                if (!pmConfigMaskSetInMetadata(NULL, NULL, source)) {
    147123                    psError(PS_ERR_UNKNOWN, false, "Unable to set mask bits.");
    148124                    return 0;
    149125                }
    150                 value = psMetadataLookupU8(&mdok, source, name);
     126                value = psMetadataLookupImageMaskFromGeneric(&mdok, source, name);
    151127                psAssert(mdok, "Should have generated mask value");
    152128            } else {
     
    163139}
    164140
     141// lookup an image mask value by name from a psMetadata, without requiring the entry to
     142// be of type psImageMaskType, but verifying that it will fit in psImageMaskType
     143psImageMaskType psMetadataLookupImageMaskFromGeneric (bool *status, const psMetadata *md, const char *name) {
     144
     145    *status = true;
     146
     147        // select the mask bit name from the header
     148        psMetadataItem *item = psMetadataLookup (md, name);
     149        if (!item) {
     150            psWarning("Unable to find header keyword %s when parsing mask", name);
     151            *status = false;
     152            return 0;
     153        }
     154
     155        // the value may be any of the U8, U16, U32, U64 types : accept the value regardless of type size
     156        psU64 fullValue = 0;
     157        switch (item->type) {
     158          case PS_DATA_U8:
     159            fullValue = item->data.U8;
     160            break;
     161          case PS_DATA_U16:
     162            fullValue = item->data.U16;
     163            break;
     164          case PS_DATA_U32:
     165            fullValue = item->data.U32;
     166            break;
     167          case PS_DATA_U64:
     168            fullValue = item->data.U64;
     169            break;
     170          case PS_DATA_S8:
     171            fullValue = item->data.S8;
     172            break;
     173          case PS_DATA_S16:
     174            fullValue = item->data.S16;
     175            break;
     176          case PS_DATA_S32:
     177            fullValue = item->data.S32;
     178            break;
     179          case PS_DATA_S64:
     180            fullValue = item->data.S64;
     181            break;
     182          default:
     183            psWarning("Mask entry %s in metadata is not of a mask type", name);
     184            *status = false;
     185            return 0;
     186        }
     187
     188        // will the incoming value fit within the current image mask type?
     189        if (fullValue > PS_MAX_IMAGE_MASK_TYPE) {
     190            psWarning("Mask entry %s in metadata is larger than allowed by the psImageMaskType", name);
     191            *status = false;
     192            return 0;
     193        }
     194        psImageMaskType value = fullValue;
     195        // XXX validate that value is a 2^n value?
     196
     197        return value;
     198}
     199
    165200// Remove from the header keywords starting with the provided string
    166 static int maskRemoveHeader(psMetadata *header, // Header from which to remove keywords
    167                             const char *start // Remove keywords that start with this string
    168                             )
     201int pmConfigMaskRemoveHeaderKeywords(psMetadata *header, // Header from which to remove keywords
     202                                     const char *start // Remove keywords that start with this string
     203    )
    169204{
    170205    psString regex = NULL;              // Regular expression for keywords
     
    182217}
    183218
     219// look up the named mask value(s) from the MASKS recipe in the config system
     220psImageMaskType pmConfigMaskGet(const char *masks, const pmConfig *config)
     221{
     222    psAssert(config, "Require configuration");
     223    PS_ASSERT_STRING_NON_EMPTY(masks, 0);
     224
     225    bool mdok;                          // Status of MD lookup
     226    psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, "MASKS"); // The recipe
     227    if (!recipe) {
     228        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     229        return 0;
     230    }
     231   
     232    psImageMaskType mask = pmConfigMaskGetFromMetadata (recipe, masks);
     233    return mask;
     234}
     235
     236bool pmConfigMaskSet(const pmConfig *config, const char *maskName, psImageMaskType maskValue)
     237{
     238    psAssert(config, "Require configuration");
     239    PS_ASSERT_STRING_NON_EMPTY(maskName, false);
     240
     241    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     242    if (!recipe) {
     243        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     244        return false;
     245    }
     246
     247    bool status = psMetadataAddImageMask(recipe, PS_LIST_TAIL, maskName, PS_META_REPLACE, NULL, maskValue);
     248    return status;
     249}
     250
     251
     252// replace the named masks in the recipe with values in the header:
     253// replace only the names in the header in the recipe
     254bool pmConfigMaskReadHeader(pmConfig *config, const psMetadata *header)
     255{
     256    PS_ASSERT_PTR_NON_NULL(config, false);
     257    PS_ASSERT_METADATA_NON_NULL(header, false);
     258
     259    bool status = false;
     260
     261    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     262    if (!recipe) {
     263        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     264        return false;
     265    }
     266
     267    // MASK.VALUE and MARK.VALUE aren't usually set in the recipe, but may be set in the header: create fake
     268    // versions so that it won't complain later
     269    if (!psMetadataLookup(recipe, "MASK.VALUE")) {
     270        psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MASK.VALUE", 0, "Bits to mask", 0);
     271    }
     272    if (!psMetadataLookup(recipe, "MARK.VALUE")) {
     273        psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MARK.VALUE", 0, "Bits for marking", 0);
     274    }
     275
     276    // How many mask values do we need to read?  We raise an error if this is not found,
     277    // unless the MASK.FORCE is set to true in the camera config
     278    int nMask = psMetadataLookupS32(&status, header, "MSKNUM");
     279    if (!status) {
     280        if (psMetadataLookupBool(&status, config->camera, "MASK.FORCE")) {
     281            psWarning("No mask values in header.  Assuming MASKS recipe is accurate because of MASK.FORCE");
     282            return true;
     283        }
     284        psError(PS_ERR_UNKNOWN, true, "Unable to find MSKNUM in header.");
     285        return false;
     286    }
     287
     288    // Loop over the expected number of header mask names.  For each named mask value, there
     289    // should be a pair of header keywords, one for the name and one for the value
     290    char namekey[80];                   // Keyword name for symbolic name of mask entry
     291    char valuekey[80];                  // Keyword name for value of mask entry
     292    for (int i = 0; i < nMask; i++) {
     293        snprintf(namekey,  64, "MSKNAM%02d", i);
     294        snprintf(valuekey, 64, "MSKVAL%02d", i);
     295
     296        char *name = psMetadataLookupStr(&status, header, namekey);
     297        if (!status || !name) {
     298            psWarning("Unable to find header keyword %s when parsing mask", namekey);
     299            continue;
     300        }
     301
     302        psImageMaskType headerValue = psMetadataLookupImageMaskFromGeneric (&status, header, valuekey);
     303        if (!status) {
     304            psWarning("Failed to get mask value %s from header, skipping", valuekey);
     305            continue;
     306        }           
     307
     308        // since we may read multiple mask files, we need to warn (or error?) if any of the
     309        // header mask values conflict with other header mask values; However, the original
     310        // mask values from the recipe do not need to match the header values.
     311
     312        // when we add a header mask value, we will also add the NAME.ALREADY entry; check for
     313        // the NAME.ALREADY entry to see if we have previously added this mask value from a
     314        // header.
     315
     316        psString nameAlready = NULL;    // Name of key with ".ALREADY" added
     317        psStringAppend(&nameAlready, "%s.ALREADY", name);
     318        bool already = psMetadataLookupBool(&status, recipe, nameAlready); // Already read this one?
     319
     320        bool inRecipe = false;
     321        psImageMaskType recipeValue = psMetadataLookupImageMaskFromGeneric (&inRecipe, recipe, name);
     322        if (!inRecipe) {
     323            psWarning("Mask value %s is not defined in the recipe", name);
     324        }           
     325
     326        if (already) {
     327            assert (inRecipe); // XXX makes no sense for NAME.ALREADY to be in without NAME
     328            if (recipeValue != headerValue) {
     329                psWarning("New mask header value does not match previously loaded entry: %x vs %x", headerValue, recipeValue);
     330                psMetadataAddImageMask(recipe, PS_LIST_TAIL, name, PS_META_REPLACE, "Bitmask bit value", headerValue);
     331                // XXX alternatively, error here
     332            }
     333        } else {
     334            psMetadataAddBool(recipe, PS_LIST_TAIL, nameAlready, 0, "Already read this mask value", true);
     335            psMetadataAddImageMask(recipe, PS_LIST_TAIL, name, PS_META_REPLACE, "Bitmask bit value", headerValue);
     336        }
     337
     338        psFree(nameAlready);
     339    }
     340
     341    return true;
     342}
     343
     344// write the named mask bits to the header
     345bool pmConfigMaskWriteHeader(const pmConfig *config, psMetadata *header)
     346{
     347    PS_ASSERT_PTR_NON_NULL(config, false);
     348    PS_ASSERT_METADATA_NON_NULL(header, false);
     349
     350    pmConfigMaskRemoveHeaderKeywords(header, "MSKNAM");
     351    pmConfigMaskRemoveHeaderKeywords(header, "MSKVAL");
     352    if (psMetadataLookup(header, "MSKNUM")) {
     353        psMetadataRemoveKey(header, "MSKNUM");
     354    }
     355
     356    char namekey[80];
     357    char valuekey[80];
     358
     359    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     360    if (!recipe) {
     361        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     362        return false;
     363    }
     364
     365    int nMask = 0;
     366
     367    psMetadataIterator *iter = psMetadataIteratorAlloc(recipe, PS_LIST_HEAD, NULL); // Iterator
     368    psMetadataItem *item;               // Item from iteration
     369    while ((item = psMetadataGetAndIncrement(iter))) {
     370
     371        // XXX this would give a false positive for mask which include '.ALREADY' in their names
     372        char *ptr = strstr (item->name, ".ALREADY");
     373        if (ptr) continue;
     374
     375        psU64 fullValue = 0;
     376        switch (item->type) {
     377          case PS_DATA_U8:
     378            fullValue = item->data.U8;
     379            break;
     380          case PS_DATA_U16:
     381            fullValue = item->data.U16;
     382            break;
     383          case PS_DATA_U32:
     384            fullValue = item->data.U32;
     385            break;
     386          case PS_DATA_U64:
     387            fullValue = item->data.U64;
     388            break;
     389          default:
     390            psWarning("mask recipe entry %s is not a bit value\n", item->name);
     391            continue;
     392        }
     393        assert (fullValue <= PS_MAX_IMAGE_MASK_TYPE); // this should have been asserted on read...
     394
     395        snprintf(namekey,  64, "MSKNAM%02d", nMask);
     396        snprintf(valuekey, 64, "MSKVAL%02d", nMask);
     397
     398        psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
     399        psMetadataAddImageMask(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", fullValue);
     400        nMask++;
     401    }
     402    psFree(iter);
     403
     404    psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Bitmask bit count", nMask);
     405    return true;
     406}
     407
     408
     409bool pmConfigMaskSetBits(psImageMaskType *outMaskValue, psImageMaskType *outMarkValue, const pmConfig *config)
     410{
     411    PS_ASSERT_PTR_NON_NULL(config, false);
     412
     413    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     414    if (!recipe) {
     415        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     416        return false;
     417    }
     418
     419    bool status = pmConfigMaskSetInMetadata(outMaskValue, outMarkValue, recipe);
     420    return status;
     421}
     422
    184423//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    185424// FPA version of mask functions.  These are not ready to go yet.
     
    187426
    188427#if 0
    189 bool pmFPAMaskSetValues(psMaskType *outMaskValue, psMaskType *outMarkValue, pmFPA *fpa)
    190 {
     428
     429bool pmFPAMaskWriteHeader(psMetadata *header, const pmFPA *fpa)
     430{
     431    PS_ASSERT_METADATA_NON_NULL(header, false);
    191432    PS_ASSERT_PTR_NON_NULL(fpa, false);
    192433
     434    // clear out the header of the associated keywords:
     435    pmConfigMaskRemoveHeaderKeywords(header, "MSKNAM");
     436    pmConfigMaskRemoveHeaderKeywords(header, "MSKVAL");
     437    if (psMetadataLookup(header, "MSKNUM")) {
     438        psMetadataRemoveKey(header, "MSKNUM");
     439    }
     440
     441    char namekey[80], valuekey[80];     // Mask name and mask value header keywords
     442    int numMask = 0;                    // Number of mask entries
     443
     444    psMetadataIterator *iter = psMetadataIteratorAlloc(fpa->masks, PS_LIST_HEAD, NULL); // Iterator
     445    psMetadataItem *item;               // Item from iteration
     446    while ((item = psMetadataGetAndIncrement(iter))) {
     447        if (item->type != PS_TYPE_IMAGE_MASK) {
     448            psWarning("mask recipe entry %s is not of a mask type (%x)", item->name, item->type);
     449            continue;
     450        }
     451
     452        snprintf(namekey,  64, "MSKNAM%02d", numMask);
     453        snprintf(valuekey, 64, "MSKVAL%02d", numMask);
     454
     455        psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
     456        psMetadataAddImageMask(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", item->data.PS_TYPE_IMAGE_MASK_DATA);
     457        numMask++;
     458    }
     459    psFree(iter);
     460
     461    return psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Number of named mask entries", numMask);
     462}
     463
     464bool pmFPAMaskSetValues(psImageMaskType *outMaskValue, psImageMaskType *outMarkValue, pmFPA *fpa)
     465{
     466    PS_ASSERT_PTR_NON_NULL(fpa, false);
     467
    193468    return maskSetValues(outMaskValue, outMarkValue, fpa->masks);
    194469}
    195470
    196 psMaskType pmFPAMaskGet(const pmFPA *fpa, const char *masks, const pmConfig *config)
     471psImageMaskType pmFPAMaskGet(const pmFPA *fpa, const char *masks, const pmConfig *config)
    197472{
    198473    PS_ASSERT_PTR_NON_NULL(fpa, 0);
     
    201476
    202477    if (fpa->masks) {
    203         return maskGet(fpa->masks, masks);
     478        return pmConfigMaskGetFromMetadata(fpa->masks, masks);
    204479    }
    205480    return pmConfigMaskGet(masks, config);
    206481}
    207482
    208 bool pmFPAMaskSet(pmFPA *fpa, const char *maskName, psMaskType maskValue)
     483bool pmFPAMaskSet(pmFPA *fpa, const char *maskName, psImageMaskType maskValue)
    209484{
    210485    PS_ASSERT_PTR_NON_NULL(fpa, 0);
     
    214489        fpa->masks = psMetadataAlloc();
    215490    }
    216     return psMetadataAddU8(fpa->masks, PS_LIST_TAIL, maskName, PS_META_REPLACE, NULL, maskValue);
     491    return psMetadataAddImageMask(fpa->masks, PS_LIST_TAIL, maskName, PS_META_REPLACE, NULL, maskValue);
    217492}
    218493
     
    250525            continue;
    251526        }
    252         psU8 bit = psMetadataLookupU8(&mdok, header, valuekey);
     527        psImageMaskType bit = psMetadataLookupImageMask(&mdok, header, valuekey);
    253528        if (!mdok) {
    254529            psWarning("Unable to find header keyword %s when parsing mask", namekey);
     
    260535        psMetadataItem *item = psMetadataLookup(fpa->masks, name); // Item in recipe with current value
    261536        if (item) {
    262             psAssert(item->type == PS_TYPE_MASK, "Mask entry %s is not of a mask type (%x)",
     537            psAssert(item->type == PS_TYPE_IMAGE_MASK, "Mask entry %s is not of a mask type (%x)",
    263538                     name, item->type);
    264             if (item->data.PS_TYPE_MASK_DATA != bit) {
     539            if (item->data.PS_TYPE_IMAGE_MASK_DATA != bit) {
    265540                psWarning("New mask entry %s doesn't match previously loaded entry: %x vs %x",
    266                           name, bit, item->data.PS_TYPE_MASK_DATA);
     541                          name, bit, item->data.PS_TYPE_IMAGE_MASK_DATA);
    267542            }
    268543        } else {
    269             psMetadataAddU8(fpa->masks, PS_LIST_TAIL, name, 0, NULL, bit);
     544            psMetadataAddImageMask(fpa->masks, PS_LIST_TAIL, name, 0, NULL, bit);
    270545        }
    271546    }
     
    281556    psMetadataItem *item;               // Item from iteration
    282557    while ((item = psMetadataGetAndIncrement(iter))) {
    283         if (item->type != PS_TYPE_MASK) {
     558        if (item->type != PS_TYPE_IMAGE_MASK) {
    284559            psWarning("Recipe mask entry %s is not of a mask type (%x)", item->name, item->type);
    285560            continue;
    286561        }
    287562        if (!psMetadataLookup(fpa->masks, item->name)) {
    288             psMetadataAddU8(fpa->masks, PS_LIST_TAIL, item->name, 0, item->comment,
    289                             item->data.PS_TYPE_MASK_DATA);
     563            psMetadataAddImageMask(fpa->masks, PS_LIST_TAIL, item->name, 0, item->comment,
     564                            item->data.PS_TYPE_IMAGE_MASK_DATA);
    290565        }
    291566    }
     
    294569    return true;
    295570}
    296 
    297 
    298 bool pmFPAMaskWriteHeader(psMetadata *header, const pmFPA *fpa)
    299 {
    300     PS_ASSERT_METADATA_NON_NULL(header, false);
    301     PS_ASSERT_PTR_NON_NULL(fpa, false);
    302 
    303     maskRemoveHeader(header, "MSKNAM");
    304     maskRemoveHeader(header, "MSKVAL");
    305     if (psMetadataLookup(header, "MSKNUM")) {
    306         psMetadataRemoveKey(header, "MSKNUM");
    307     }
    308 
    309     char namekey[80], valuekey[80];     // Mask name and mask value header keywords
    310     int numMask = 0;                    // Number of mask entries
    311 
    312     psMetadataIterator *iter = psMetadataIteratorAlloc(fpa->masks, PS_LIST_HEAD, NULL); // Iterator
    313     psMetadataItem *item;               // Item from iteration
    314     while ((item = psMetadataGetAndIncrement(iter))) {
    315         if (item->type != PS_TYPE_MASK) {
    316             psWarning("mask recipe entry %s is not of a mask type (%x)", item->name, item->type);
    317             continue;
    318         }
    319 
    320         snprintf(namekey,  64, "MSKNAM%02d", numMask);
    321         snprintf(valuekey, 64, "MSKVAL%02d", numMask);
    322 
    323         psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
    324         psMetadataAddU8(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", item->data.PS_TYPE_MASK_DATA);
    325         numMask++;
    326     }
    327     psFree(iter);
    328 
    329     return psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Number of named mask entries", numMask);
    330 }
    331 
    332571#endif
    333 
    334 
    335 psMaskType pmConfigMaskGet(const char *masks, const pmConfig *config)
    336 {
    337     psAssert(config, "Require configuration");
    338     PS_ASSERT_STRING_NON_EMPTY(masks, 0);
    339 
    340     bool mdok;                          // Status of MD lookup
    341     psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, "MASKS"); // The recipe
    342     if (!recipe) {
    343         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    344         return 0;
    345     }
    346     return maskGet(recipe, masks);
    347 }
    348 
    349 
    350 bool pmConfigMaskSet(const pmConfig *config, const char *maskName, psMaskType maskValue)
    351 {
    352     psAssert(config, "Require configuration");
    353     PS_ASSERT_STRING_NON_EMPTY(maskName, false);
    354 
    355     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    356     if (!recipe) {
    357         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    358         return false;
    359     }
    360 
    361     return psMetadataAddU8(recipe, PS_LIST_TAIL, maskName, PS_META_REPLACE, NULL, maskValue);
    362 }
    363 
    364 
    365 // replace the named masks in the recipe with values in the header:
    366 // replace only the names in the header in the recipe
    367 bool pmConfigMaskReadHeader(pmConfig *config, const psMetadata *header)
    368 {
    369     PS_ASSERT_PTR_NON_NULL(config, false);
    370     PS_ASSERT_METADATA_NON_NULL(header, false);
    371 
    372     bool status = false;
    373 
    374     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    375     if (!recipe) {
    376         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    377         return false;
    378     }
    379 
    380     // MASK.VALUE and MARK.VALUE aren't usually set in the recipe, but may be set in the header: create fake
    381     // versions so that it won't complain later
    382     if (!psMetadataLookup(recipe, "MASK.VALUE")) {
    383         psMetadataAddU8(recipe, PS_LIST_TAIL, "MASK.VALUE", 0, "Bits to mask", 0);
    384     }
    385     if (!psMetadataLookup(recipe, "MARK.VALUE")) {
    386         psMetadataAddU8(recipe, PS_LIST_TAIL, "MARK.VALUE", 0, "Bits for marking", 0);
    387     }
    388 
    389     int nMask = psMetadataLookupS32(&status, header, "MSKNUM");
    390     if (!status) {
    391         if (psMetadataLookupBool(&status, config->camera, "MASK.FORCE")) {
    392             psWarning("No mask values in header.  Assuming MASKS recipe is accurate because of MASK.FORCE");
    393             return true;
    394         }
    395         psError(PS_ERR_UNKNOWN, true, "Unable to find MSKNUM in header.");
    396         return false;
    397     }
    398 
    399     char namekey[80];                   // Keyword name for symbolic name of mask entry
    400     char valuekey[80];                  // Keyword name for value of mask entry
    401     for (int i = 0; i < nMask; i++) {
    402         snprintf(namekey,  64, "MSKNAM%02d", i);
    403         snprintf(valuekey, 64, "MSKVAL%02d", i);
    404 
    405         char *name = psMetadataLookupStr(&status, header, namekey);
    406         if (!status || !name) {
    407             psWarning("Unable to find header keyword %s when parsing mask", namekey);
    408             continue;
    409         }
    410         psU8 bit = psMetadataLookupU8(&status, header, valuekey);
    411         if (!status) {
    412             psWarning("Unable to find header keyword %s when parsing mask", namekey);
    413             continue;
    414         }
    415 
    416         // XXX validate that bit is a 2^n value?
    417 
    418         psString nameAlready = NULL;    // Name of key with ".ALREADY" added
    419         psStringAppend(&nameAlready, "%s.ALREADY", name);
    420         bool already = psMetadataLookupBool(&status, recipe, nameAlready); // Already read this one?
    421 
    422         psMetadataItem *item = psMetadataLookup(recipe, name); // Item in recipe with current value
    423         if (item && item->type != PS_TYPE_MASK) {
    424             psWarning("Mask recipe entry is not of a mask type (%x)", item->type);
    425             item->type = PS_TYPE_MASK;
    426         }
    427 
    428         if (already) {
    429             if (item && item->data.U8 != bit) {
    430                 psWarning("New mask recipe entry doesn't match previously loaded entry: %x vs %x",
    431                           bit, item->data.U8);
    432             }
    433         } else {
    434             psMetadataAddBool(recipe, PS_LIST_TAIL, nameAlready, 0, "Already read this mask value", true);
    435         }
    436 
    437         if (!item) {
    438             psWarning("Mask recipe entry %s not in recipe\n", name);
    439             psMetadataAddU8(recipe, PS_LIST_TAIL, name, 0, "Bitmask bit value", bit);
    440         } else {
    441             item->data.U8 = bit;
    442         }
    443 
    444         psFree(nameAlready);
    445     }
    446 
    447 
    448     return true;
    449 }
    450 
    451 
    452 
    453 // write the named mask bits to the header
    454 bool pmConfigMaskWriteHeader(const pmConfig *config, psMetadata *header)
    455 {
    456     PS_ASSERT_PTR_NON_NULL(config, false);
    457     PS_ASSERT_METADATA_NON_NULL(header, false);
    458 
    459     maskRemoveHeader(header, "MSKNAM");
    460     maskRemoveHeader(header, "MSKVAL");
    461     if (psMetadataLookup(header, "MSKNUM")) {
    462         psMetadataRemoveKey(header, "MSKNUM");
    463     }
    464 
    465     char namekey[80];
    466     char valuekey[80];
    467 
    468     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    469     if (!recipe) {
    470         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    471         return false;
    472     }
    473 
    474     int nMask = 0;
    475 
    476     psMetadataIterator *iter = psMetadataIteratorAlloc(recipe, PS_LIST_HEAD, NULL); // Iterator
    477     psMetadataItem *item;               // Item from iteration
    478     while ((item = psMetadataGetAndIncrement(iter))) {
    479         if (strcmp(item->name + strlen(item->name) - strlen(".ALREADY"), ".ALREADY") == 0) {
    480             continue;
    481         }
    482 
    483         if (item->type != PS_DATA_U8) {
    484             psWarning("mask recipe entry %s is not a bit value\n", item->name);
    485             continue;
    486         }
    487 
    488         snprintf(namekey,  64, "MSKNAM%02d", nMask);
    489         snprintf(valuekey, 64, "MSKVAL%02d", nMask);
    490 
    491         psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
    492         psMetadataAddU8(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", item->data.U8);
    493         nMask++;
    494     }
    495     psFree(iter);
    496 
    497     psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Bitmask bit count", nMask);
    498     return true;
    499 }
    500 
    501 
    502 bool pmConfigMaskSetBits(psMaskType *outMaskValue, psMaskType *outMarkValue, const pmConfig *config)
    503 {
    504     PS_ASSERT_PTR_NON_NULL(config, false);
    505 
    506     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    507     if (!recipe) {
    508         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    509         return false;
    510     }
    511 
    512     return maskSetValues(outMaskValue, outMarkValue, recipe);
    513 }
Note: See TracChangeset for help on using the changeset viewer.