00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <map>
00021
00022 #include <archon/util/text.H>
00023 #include <archon/util/pixel_format.H>
00024
00025
00026 namespace Archon
00027 {
00028 namespace Utilities
00029 {
00030 namespace
00031 {
00032 struct WordTypeDescriptor
00033 {
00034 PixelFormat::WordType type;
00035 string tag;
00036 int width;
00037 bool isFloat;
00038
00039 WordTypeDescriptor() {}
00040
00041 WordTypeDescriptor(PixelFormat::WordType type, string tag, int width,
00042 bool isFloat):
00043 type(type), tag(tag), width(width), isFloat(isFloat) {}
00044 };
00045
00046 struct WordTypeRegistry
00047 {
00048 map<PixelFormat::WordType, WordTypeDescriptor> typeMap;
00049 map<string, WordTypeDescriptor> tagMap;
00050 map<int, WordTypeDescriptor> intWidthMap;
00051 map<int, WordTypeDescriptor> floatWidthMap;
00052
00053 template<typename T> void addDescriptor(PixelFormat::WordType type, string tag)
00054 {
00055 int width = sizeof(T) * numeric_limits<unsigned char>::digits;
00056 bool isFloat = !numeric_limits<T>::is_integer;
00057 WordTypeDescriptor d(type, tag, width, isFloat);
00058 typeMap[type] = tagMap[tag] = d;
00059 if(isFloat) floatWidthMap[width] = d;
00060 else intWidthMap[width] = d;
00061 }
00062
00063 WordTypeRegistry()
00064 {
00065 addDescriptor<unsigned char> (PixelFormat::std_char, "char");
00066 addDescriptor<unsigned short> (PixelFormat::std_short, "short");
00067 addDescriptor<unsigned int> (PixelFormat::std_int, "int");
00068 addDescriptor<unsigned long> (PixelFormat::std_long, "long");
00069 addDescriptor<PixelFormat::MaxInt> (PixelFormat::std_max_int, "max_int");
00070 addDescriptor<float> (PixelFormat::std_float, "float");
00071 addDescriptor<double> (PixelFormat::std_double, "double");
00072 addDescriptor<long double> (PixelFormat::std_long_double, "long_double");
00073 }
00074 };
00075
00076 const WordTypeRegistry &getWordTypeRegistry()
00077 {
00078 static WordTypeRegistry registry;
00079 return registry;
00080 }
00081
00082 const WordTypeDescriptor &getWordTypeDescriptor(PixelFormat::WordType type)
00083 {
00084 return getWordTypeRegistry().typeMap.find(type)->second;
00085 }
00086 }
00087
00095 PixelFormat PixelFormat::getExpandedFormat()
00096 const throw(UnsupportedWordTypeException, InconsistencyException)
00097 {
00098 cerr << "PixelFormat::getExpandedFormat: ---------------" << endl;
00099 PixelFormat complete;
00100 complete.formatType = formatType;
00101 complete.mostSignificantBitsFirst = mostSignificantBitsFirst;
00102
00103
00104
00105 WordTypeDescriptor wordTypeDescriptor;
00106 if(wordType == custom_int)
00107 {
00108 map<int, WordTypeDescriptor>::const_iterator i =
00109 getWordTypeRegistry().intWidthMap.find(bitsPerWord);
00110 if(i == getWordTypeRegistry().intWidthMap.end())
00111 ARCHON_THROW(UnsupportedWordTypeException);
00112 wordTypeDescriptor = i->second;
00113 }
00114 else if(wordType == custom_float)
00115 {
00116 map<int, WordTypeDescriptor>::const_iterator i =
00117 getWordTypeRegistry().floatWidthMap.find(bitsPerWord);
00118 if(i == getWordTypeRegistry().floatWidthMap.end())
00119 ARCHON_THROW(UnsupportedWordTypeException);
00120 wordTypeDescriptor = i->second;
00121 }
00122 else
00123 {
00124 wordTypeDescriptor = getWordTypeDescriptor(wordType);
00125 if(bitsPerWord && wordTypeDescriptor.width != bitsPerWord)
00126 ARCHON_THROW1(InconsistencyException, "Conflicting bits per word ("+
00127 Text::toString(bitsPerWord)+") specified for standard "
00128 "word type ("+wordTypeDescriptor.tag+")");
00129 }
00130 complete.wordType = wordTypeDescriptor.type;
00131 complete.bitsPerWord = wordTypeDescriptor.width;
00132 if(wordTypeDescriptor.isFloat && formatType != direct)
00133 ARCHON_THROW1(InconsistencyException, "Only direct formats can be "
00134 "used with floating point word types");
00135 cerr << "PixelFormat::getExpandedFormat: wordType: " << wordTypeDescriptor.tag << endl;
00136 cerr << "PixelFormat::getExpandedFormat: bitsPerWord: " << complete.bitsPerWord << endl;
00137
00138
00139 int numberOfChannels;
00140 switch(colorScheme)
00141 {
00142 case luminance:
00143 numberOfChannels = hasAlphaChannel ? 2 : 1;
00144 break;
00145
00146 case rgb:
00147 case hsv:
00148 numberOfChannels = hasAlphaChannel ? 4 : 3;
00149 break;
00150
00151 default:
00152 numberOfChannels = 0;
00153 }
00154 if(numberOfChannels)
00155 {
00156 if(channelLayout.size() &&
00157 numberOfChannels != static_cast<int>(channelLayout.size()))
00158 ARCHON_THROW1(InconsistencyException, "Mismatching number of "
00159 "channels in channel layout and color scheme");
00160 }
00161 else numberOfChannels =
00162 channelLayout.size() ? channelLayout.size() :
00163 pixelSize ? pixelSize : hasAlphaChannel ? 2 : 1;
00164
00165
00166
00167 if(pixelSize) complete.pixelSize = pixelSize;
00168 else switch(formatType)
00169 {
00170 case direct:
00171
00172 complete.pixelSize = numberOfChannels;
00173 break;
00174
00175 case packed:
00176 case tight:
00177 int bitsPerPixel;
00178 if(channelLayout.empty()) bitsPerPixel = numberOfChannels;
00179 else
00180 {
00181 int maxOffsetIndex = -1;
00182 int minWidth = 0;
00183 for(int i=0; i<static_cast<int>(channelLayout.size()); ++i)
00184 {
00185 const Channel &c = channelLayout[i];
00186 if(maxOffsetIndex < 0 || channelLayout[maxOffsetIndex].offset < c.offset) maxOffsetIndex = i;
00187 if(!minWidth || c.width < minWidth) minWidth = c.width;
00188 }
00189 const Channel &c = channelLayout[maxOffsetIndex];
00190 bitsPerPixel = c.offset + (c.width ? c.width : minWidth ? minWidth : 1);
00191 }
00192 complete.pixelSize = formatType == packed ?
00193 (numberOfChannels - 1) / complete.bitsPerWord + 1 : numberOfChannels;
00194 break;
00195 }
00196 cerr << "PixelFormat::getExpandedFormat: pixelSize: " << complete.pixelSize << " " << (complete.formatType == tight ? "bits" : "words") << endl;
00197
00198
00199
00200 if(channelLayout.empty())
00201 {
00202 complete.channelLayout.resize(numberOfChannels);
00203 switch(formatType)
00204 {
00205 case direct:
00206 if(complete.pixelSize < numberOfChannels)
00207 ARCHON_THROW1(InconsistencyException, "Words per pixel less than number of channels for direct format");
00208 for(int i=0; i<numberOfChannels; ++i)
00209 {
00210 Channel &c = complete.channelLayout[i];
00211 c.offset = i;
00212 c.width = complete.bitsPerWord;
00213 }
00214 break;
00215
00216 case packed:
00217 if(complete.pixelSize*complete.bitsPerWord < numberOfChannels)
00218 ARCHON_THROW1(InconsistencyException, "Bits per pixel less than number of channels for packed format");
00219 {
00220 int o = 0;
00221 int w = complete.pixelSize*complete.bitsPerWord / numberOfChannels;
00222 for(int i=0; i<numberOfChannels; ++i)
00223 {
00224 Channel &c = complete.channelLayout[i];
00225 c.offset = o;
00226 c.width = w;
00227 o += w;
00228 }
00229 }
00230 break;
00231
00232 case tight:
00233 if(complete.pixelSize < numberOfChannels)
00234 ARCHON_THROW1(InconsistencyException, "Bits per pixel less than number of channels for tight format");
00235 {
00236 int o = 0;
00237 int w = complete.pixelSize / numberOfChannels;
00238 for(int i=0; i<numberOfChannels; ++i)
00239 {
00240 Channel &c = complete.channelLayout[i];
00241 c.offset = o;
00242 c.width = w;
00243 o += w;
00244 }
00245 }
00246 break;
00247 }
00248 }
00249 else
00250 {
00251 vector<int> v(formatType == packed ? complete.pixelSize*complete.bitsPerWord : complete.pixelSize, -1);
00252 for(int i=0; i<numberOfChannels; ++i)
00253 {
00254 int o = channelLayout[i].offset;
00255 if(o < 0 || static_cast<int>(v.size()) <= o) ARCHON_THROW1(InconsistencyException, "Channel "+Text::toString(i)+" offset escapes pixel boundary");
00256 int &w = v[o];
00257 if(w != -1) ARCHON_THROW1(InconsistencyException, "Multiple channels at offset "+Text::toString(o));
00258 w = i;
00259 }
00260 complete.channelLayout = channelLayout;
00261 int maxIntBits = sizeof(MaxInt)*numeric_limits<unsigned char>::digits;
00262 for(int i=0; i<numberOfChannels; ++i)
00263 {
00264 Channel &c = complete.channelLayout[i];
00265 int &w = c.width;
00266 if(w < 0) ARCHON_THROW1(InconsistencyException, "Channel "+Text::toString(i)+" width negative");
00267 if(maxIntBits < w) ARCHON_THROW1(InconsistencyException, "Channel "+Text::toString(i)+" too wide for your CPU architecture");
00268 if(w && wordTypeDescriptor.isFloat && w != bitsPerWord) ARCHON_THROW1(InconsistencyException, "Channel "+Text::toString(i)+" width differs from word width for floating point channel");
00269 switch(formatType)
00270 {
00271 case direct:
00272
00273 if(!w) w = complete.bitsPerWord;
00274 else if(complete.bitsPerWord < w) ARCHON_THROW1(InconsistencyException, "Channel "+Text::toString(i)+" wider than word type for direct format");
00275 break;
00276
00277 case packed:
00278 case tight:
00279
00280 int j = c.offset+1;
00281 while(j < static_cast<int>(v.size()) && v[j] == -1) ++j;
00282 int maxWidth = j - c.offset;
00283 if(maxIntBits < maxWidth) maxWidth = maxIntBits;
00284 if(!w) w = maxWidth;
00285 else if(maxWidth <= w)
00286 {
00287 if(j == static_cast<int>(v.size()))
00288 ARCHON_THROW1(InconsistencyException, "Channel "+Text::toString(i)+" too wide - extends beyond pixel boundary");
00289 else ARCHON_THROW1(InconsistencyException, "Channel "+
00290 Text::toString(i)+" too wide - overlaps "
00291 "next channel ("+Text::toString(v[j])+")");
00292 }
00293 break;
00294 }
00295 }
00296 }
00297 cerr << "PixelFormat::getExpandedFormat: channelLayout:";
00298 for(int i=0; i<static_cast<int>(complete.channelLayout.size()); ++i)
00299 {
00300 cerr << " (" << complete.channelLayout[i].offset << ", " << complete.channelLayout[i].width << ")";
00301 }
00302 cerr << endl;
00303
00304
00305
00306 if(colorScheme == implied)
00307 {
00308 switch(numberOfChannels)
00309 {
00310 case 1:
00311 complete.colorScheme = luminance;
00312 complete.hasAlphaChannel = false;
00313 break;
00314
00315 case 2:
00316 complete.colorScheme = luminance;
00317 complete.hasAlphaChannel = true;
00318 break;
00319
00320 case 3:
00321 complete.colorScheme = rgb;
00322 complete.hasAlphaChannel = false;
00323 break;
00324
00325 case 4:
00326 complete.colorScheme = rgb;
00327 complete.hasAlphaChannel = true;
00328 break;
00329
00330 default:
00331 complete.colorScheme = custom;
00332 complete.hasAlphaChannel = false;
00333 break;
00334 }
00335 }
00336 else
00337 {
00338 complete.colorScheme = colorScheme;
00339 complete.hasAlphaChannel = hasAlphaChannel;
00340 }
00341 cerr << "PixelFormat::getExpandedFormat: colorScheme: " << (complete.colorScheme == luminance ? "luminance" :
00342 complete.colorScheme == rgb ? "rgb" :
00343 complete.colorScheme == hsv ? "hsv" :
00344 complete.colorScheme == custom ? "custom" : "implied") << endl;
00345 cerr << "PixelFormat::getExpandedFormat: hasAlphaChannel: " << complete.hasAlphaChannel << endl;
00346
00347
00348 return complete;
00349 }
00350
00351
00352 PixelFormat PixelFormat::getReducedFormat() const
00353 throw(UnsupportedWordTypeException, InconsistencyException)
00354 {
00355 PixelFormat expanded = getExpandedFormat();
00356 PixelFormat reduced = expanded;
00357
00358
00359 for(int i=0; i<static_cast<int>(reduced.channelLayout.size()); ++i)
00360 {
00361 PixelFormat f = reduced;
00362 f.channelLayout[i].width = 0;
00363 if(f.getExpandedFormat() == expanded) reduced = f;
00364 }
00365
00366
00367 {
00368 PixelFormat f = reduced;
00369 f.channelLayout.clear();
00370 if(f.getExpandedFormat() == expanded) reduced = f;
00371 }
00372
00373
00374 {
00375 PixelFormat f = reduced;
00376 f.colorScheme = implied;
00377 f.hasAlphaChannel = false;
00378 if(f.getExpandedFormat() == expanded) reduced = f;
00379 }
00380
00381
00382 {
00383 PixelFormat f = reduced;
00384 f.pixelSize = 0;
00385 if(f.getExpandedFormat() == expanded) reduced = f;
00386 }
00387
00388
00389 reduced.wordType = getWordTypeDescriptor(expanded.wordType).isFloat ?
00390 custom_float : custom_int;
00391
00392 return reduced;
00393 }
00394
00395
00396 string PixelFormat::toString() const
00397 {
00398 PixelFormat expanded = getExpandedFormat();
00399 PixelFormat reduced = expanded.getReducedFormat();
00400 string s = expanded.formatType == packed ? "packed" :
00401 expanded.formatType == tight ? "tight" : "direct";
00402
00403 s += "_";
00404 s += reduced.wordType == custom_int ? "int" +
00405 Text::toString(expanded.bitsPerWord) :
00406 reduced.wordType == custom_float ? "float" +
00407 Text::toString(expanded.bitsPerWord) :
00408 getWordTypeDescriptor(reduced.wordType).tag;
00409
00410 s += "_";
00411 if(reduced.channelLayout.empty() && reduced.colorScheme == custom)
00412 {
00413
00414 s += Text::toString(reduced.pixelSize);
00415 if(expanded.hasAlphaChannel) s += "a";
00416 }
00417 else
00418 {
00419 vector<int> channelMap(expanded.formatType == packed ?
00420 expanded.pixelSize*expanded.bitsPerWord :
00421 expanded.pixelSize, -1);
00422 for(int i=0; i<static_cast<int>(expanded.channelLayout.size()); ++i)
00423 channelMap[expanded.channelLayout[i].offset] = i;
00424
00425 vector<string> colorMap;
00426 switch(expanded.colorScheme)
00427 {
00428 case implied:
00429 break;
00430
00431 case custom:
00432 {
00433 int n = expanded.channelLayout.size();
00434 if(expanded.hasAlphaChannel) --n;
00435 for(int i=0; i<n; ++i) colorMap.push_back(Text::toString(i+1)+"c");
00436 }
00437 break;
00438
00439 case luminance:
00440 colorMap.push_back("l");
00441 break;
00442
00443 case rgb:
00444 colorMap.push_back("r");
00445 colorMap.push_back("g");
00446 colorMap.push_back("b");
00447 break;
00448
00449 case hsv:
00450 colorMap.push_back("h");
00451 colorMap.push_back("s");
00452 colorMap.push_back("v");
00453 break;
00454 }
00455 colorMap.push_back("a");
00456
00457
00458
00459 bool condensedLayout = expanded.colorScheme != custom;
00460 if(condensedLayout)
00461 {
00462
00463 if(expanded.formatType == direct)
00464 {
00465 for(int i=0; i<static_cast<int>(channelMap.size()); ++i) if(channelMap[i] < 0)
00466 {
00467 condensedLayout = false;
00468 break;
00469 }
00470 }
00471 else
00472 {
00473 int i=0;
00474 while(i < static_cast<int>(channelMap.size()))
00475 {
00476 int gapSize = 0;
00477 while(i+gapSize < static_cast<int>(channelMap.size()) && channelMap[i+gapSize] < 0) ++gapSize;
00478 if(gapSize)
00479 {
00480
00481 if(i == static_cast<int>(channelMap.size()) && gapSize < expanded.bitsPerWord && expanded.formatType == packed) break;
00482
00483 condensedLayout = false;
00484 break;
00485 }
00486
00487 i += expanded.channelLayout[channelMap[i]].width;;
00488 }
00489 }
00490 }
00491
00492
00493
00494 if(expanded.formatType == direct)
00495 {
00496 for(int i=0; i<static_cast<int>(channelMap.size()); ++i)
00497 {
00498 if(i && !condensedLayout) s += "_";
00499 int j = channelMap[i];
00500 s += j < 0 ? "z" : colorMap[j];
00501 if(reduced.channelLayout.size())
00502 {
00503 int w = reduced.channelLayout[j].width;
00504 if(w) s+= Text::toString(w);
00505 }
00506 }
00507 }
00508 else
00509 {
00510 int i=0;
00511 while(i < static_cast<int>(channelMap.size()))
00512 {
00513
00514 int w = 0;
00515 while(i+w < static_cast<int>(channelMap.size()) && channelMap[i+w] < 0) ++w;
00516 if(w)
00517 {
00518
00519 if(i == static_cast<int>(channelMap.size()) && w < expanded.bitsPerWord && expanded.formatType == packed) break;
00520
00521 if(i && !condensedLayout) s += "_";
00522 s += Text::toString(w);
00523 }
00524 else
00525 {
00526 if(i && !condensedLayout) s += "_";
00527 int j = channelMap[i];
00528 w = expanded.channelLayout[j].width;
00529 s += colorMap[j] + Text::toString(w);
00530 }
00531 i += w;
00532 }
00533 }
00534 }
00535
00536 if(mostSignificantBitsFirst) s += "_msb";
00537 return s;
00538 }
00539 }
00540 }