Changeset 21183 for trunk/psModules/src/config/pmConfigMask.c
- Timestamp:
- Jan 26, 2009, 8:40:07 PM (17 years ago)
- File:
-
- 1 edited
-
trunk/psModules/src/config/pmConfigMask.c (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/config/pmConfigMask.c
r19870 r21183 9 9 #include "pmConfigMask.h" 10 10 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 11 static 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 33 25 }; 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 41 bool pmConfigMaskSetInMetadata(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned 42 psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned 43 psMetadata *source // Source of mask bits 44 ) 68 45 { 69 46 PS_ASSERT_METADATA_NON_NULL(source, false); 70 47 71 48 // 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++) { 77 55 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 79 61 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; 99 74 } 100 75 101 76 // 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; 105 81 for (int i = 0; !markValue && (i < nBits); i++) { 106 if ( maskValue & markValue) {107 mark Value >>= 1;82 if (allMasks & markTrial) { 83 markTrial <<= 1; 108 84 } else { 109 markValue = mark Value;85 markValue = markTrial; 110 86 } 111 87 } … … 116 92 117 93 // update the list with the results 118 psMetadataAdd U8(source, PS_LIST_TAIL, "MASK.VALUE", PS_META_REPLACE, NULL, maskValue);119 psMetadataAdd U8(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); 120 96 121 97 if (outMaskValue) { … … 130 106 131 107 // Get a mask value by name(s) 132 static psMaskType maskGet(psMetadata *source, // Source of masks133 const char *masks // Mask values to get134 )135 { 136 ps MaskType mask = 0; // Mask value, to return108 psImageMaskType pmConfigMaskGetFromMetadata(psMetadata *source, // Source of masks 109 const char *masks // Mask values to get 110 ) 111 { 112 psImageMaskType mask = 0; // Mask value, to return 137 113 138 114 psArray *names = psStringSplitArray(masks, " ,;", false); // Array of symbolic names … … 140 116 const char *name = names->data[i]; // Symbolic name of interest 141 117 bool mdok; // Status of MD lookup 142 ps MaskType value = psMetadataLookupU8(&mdok, source, name);118 psImageMaskType value = psMetadataLookupImageMaskFromGeneric(&mdok, source, name); 143 119 if (!mdok) { 144 120 // Try and generate the value if we can 145 121 if (strcmp(name, "MASK.VALUE") == 0 || strcmp(name, "MARK.VALUE") == 0) { 146 if (! maskSetValues(NULL, NULL, source)) {122 if (!pmConfigMaskSetInMetadata(NULL, NULL, source)) { 147 123 psError(PS_ERR_UNKNOWN, false, "Unable to set mask bits."); 148 124 return 0; 149 125 } 150 value = psMetadataLookup U8(&mdok, source, name);126 value = psMetadataLookupImageMaskFromGeneric(&mdok, source, name); 151 127 psAssert(mdok, "Should have generated mask value"); 152 128 } else { … … 163 139 } 164 140 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 143 psImageMaskType 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 165 200 // Remove from the header keywords starting with the provided string 166 static int maskRemoveHeader(psMetadata *header, // Header from which to remove keywords167 const char *start // Remove keywords that start with this string168 )201 int pmConfigMaskRemoveHeaderKeywords(psMetadata *header, // Header from which to remove keywords 202 const char *start // Remove keywords that start with this string 203 ) 169 204 { 170 205 psString regex = NULL; // Regular expression for keywords … … 182 217 } 183 218 219 // look up the named mask value(s) from the MASKS recipe in the config system 220 psImageMaskType 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 236 bool 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 254 bool 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 345 bool 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 409 bool 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 184 423 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 185 424 // FPA version of mask functions. These are not ready to go yet. … … 187 426 188 427 #if 0 189 bool pmFPAMaskSetValues(psMaskType *outMaskValue, psMaskType *outMarkValue, pmFPA *fpa) 190 { 428 429 bool pmFPAMaskWriteHeader(psMetadata *header, const pmFPA *fpa) 430 { 431 PS_ASSERT_METADATA_NON_NULL(header, false); 191 432 PS_ASSERT_PTR_NON_NULL(fpa, false); 192 433 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 464 bool pmFPAMaskSetValues(psImageMaskType *outMaskValue, psImageMaskType *outMarkValue, pmFPA *fpa) 465 { 466 PS_ASSERT_PTR_NON_NULL(fpa, false); 467 193 468 return maskSetValues(outMaskValue, outMarkValue, fpa->masks); 194 469 } 195 470 196 ps MaskType pmFPAMaskGet(const pmFPA *fpa, const char *masks, const pmConfig *config)471 psImageMaskType pmFPAMaskGet(const pmFPA *fpa, const char *masks, const pmConfig *config) 197 472 { 198 473 PS_ASSERT_PTR_NON_NULL(fpa, 0); … … 201 476 202 477 if (fpa->masks) { 203 return maskGet(fpa->masks, masks);478 return pmConfigMaskGetFromMetadata(fpa->masks, masks); 204 479 } 205 480 return pmConfigMaskGet(masks, config); 206 481 } 207 482 208 bool pmFPAMaskSet(pmFPA *fpa, const char *maskName, ps MaskType maskValue)483 bool pmFPAMaskSet(pmFPA *fpa, const char *maskName, psImageMaskType maskValue) 209 484 { 210 485 PS_ASSERT_PTR_NON_NULL(fpa, 0); … … 214 489 fpa->masks = psMetadataAlloc(); 215 490 } 216 return psMetadataAdd U8(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); 217 492 } 218 493 … … 250 525 continue; 251 526 } 252 ps U8 bit = psMetadataLookupU8(&mdok, header, valuekey);527 psImageMaskType bit = psMetadataLookupImageMask(&mdok, header, valuekey); 253 528 if (!mdok) { 254 529 psWarning("Unable to find header keyword %s when parsing mask", namekey); … … 260 535 psMetadataItem *item = psMetadataLookup(fpa->masks, name); // Item in recipe with current value 261 536 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)", 263 538 name, item->type); 264 if (item->data.PS_TYPE_ MASK_DATA != bit) {539 if (item->data.PS_TYPE_IMAGE_MASK_DATA != bit) { 265 540 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); 267 542 } 268 543 } else { 269 psMetadataAdd U8(fpa->masks, PS_LIST_TAIL, name, 0, NULL, bit);544 psMetadataAddImageMask(fpa->masks, PS_LIST_TAIL, name, 0, NULL, bit); 270 545 } 271 546 } … … 281 556 psMetadataItem *item; // Item from iteration 282 557 while ((item = psMetadataGetAndIncrement(iter))) { 283 if (item->type != PS_TYPE_ MASK) {558 if (item->type != PS_TYPE_IMAGE_MASK) { 284 559 psWarning("Recipe mask entry %s is not of a mask type (%x)", item->name, item->type); 285 560 continue; 286 561 } 287 562 if (!psMetadataLookup(fpa->masks, item->name)) { 288 psMetadataAdd U8(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); 290 565 } 291 566 } … … 294 569 return true; 295 570 } 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 keywords310 int numMask = 0; // Number of mask entries311 312 psMetadataIterator *iter = psMetadataIteratorAlloc(fpa->masks, PS_LIST_HEAD, NULL); // Iterator313 psMetadataItem *item; // Item from iteration314 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 332 571 #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 lookup341 psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, "MASKS"); // The recipe342 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 recipe356 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 recipe367 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 recipe375 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 fake381 // versions so that it won't complain later382 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 entry400 char valuekey[80]; // Keyword name for value of mask entry401 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" added419 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 value423 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 header454 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 recipe469 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); // Iterator477 psMetadataItem *item; // Item from iteration478 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 recipe507 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.
