00001
00020 #include "config.h"
00021 #include "libnebular.hpp"
00022 #include "libnebular-plugin.hpp"
00023
00024 #include <set>
00025
00026 namespace libnebular{
00027 using namespace std;
00028
00029
00030
00031
00032 #define CHECK_PROP_COND_MSG(CONDITION, PROP_NAME, COND_MSG) \
00033 if(!(CONDITION)){ \
00034 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg( \
00035 String("\"")+PROP_NAME+"\"", ( isSet(PROP_NAME) ? get<String>(PROP_NAME) : "<unset>" ), \
00036 COND_MSG , \
00037 "", "Invalid" \
00038 ) \
00039 ); \
00040 } \
00041 \
00042 while(false) \
00043
00044
00045 #define CHECK_PROP(CONDITION, PROP_NAME) CHECK_PROP_COND_MSG(CONDITION, PROP_NAME, #CONDITION)
00046
00047 class PictureProps::Impl_{
00048 private:
00049 friend class PictureProps;
00050
00051 PictureProps &p;
00052
00054 static Integer dpiToDotsPerM(Integer xInDpi){
00055 Integer DotsPerMPerDpiNumerator = 5000;
00056 Integer DotsPerMPerDpiDenominator = 127;
00057 return roundDiv(
00058 xInDpi * DotsPerMPerDpiNumerator,
00059 DotsPerMPerDpiDenominator
00060 );
00061 }
00062
00064 static Integer dotsPerMToDpi(Integer xInDotsPerM){
00065 Integer DpiPerDotsPerMNumerator = 127;
00066 Integer DpiPerDotsPerMDenominator = 5000;
00067 return roundDiv(
00068 xInDotsPerM * DpiPerDotsPerMNumerator,
00069 DpiPerDotsPerMDenominator
00070 );
00071 }
00072
00076 template <typename What> void calculateUnchecked();
00077
00078 Impl_(PictureProps &newP):
00079 p(newP)
00080 {}
00081 };
00082
00083 template <> void PictureProps::Impl_::calculateUnchecked<PictureProps::PropCalcBmColorsUsed>(){
00084 std::set<Integer> usedColors;
00085
00086 const char *pixel = p.get<Blob>("bm/data").getDataReadOnly();
00087 Integer size[2] = {
00088 p.get<Integer>("bm/x-size"),
00089 p.get<Integer>("bm/y-size")
00090 };
00091 const Integer bmBytesPerPixel = checkedBitsToIntBytes(
00092 p.get<Integer>("bm/bpp")
00093 );
00094 const Integer bmScanlineSkipInBytes = checkedBitsToIntBytes(
00095 p.get<Integer>("bm/scanline-skip")
00096 );
00097 Integer coord[2];
00098
00099 Integer bmPixelMaskColor;
00100 if(p.get<String>("bm/pixel-format-type") == "rgb"){
00101 bmPixelMaskColor =
00102 p.get<Integer>("bm/pixel-mask/r") |
00103 p.get<Integer>("bm/pixel-mask/g") |
00104 p.get<Integer>("bm/pixel-mask/b");
00105 }else if(p.get<String>("bm/pixel-format-type") == "pal"){
00106 bmPixelMaskColor = p.get<Integer>("bm/pixel-mask/pal");
00107 }else if(p.get<String>("bm/pixel-format-type") == "gray"){
00108 bmPixelMaskColor = p.get<Integer>("bm/pixel-mask/gray");
00109 }else{
00110 throw logic_error("Assumption have failed");
00111 }
00112
00113 if(p.get<String>("bm/scanline-axis") != "x"){
00114 std::swap(size[0], size[1]);
00115 }
00116
00117 for(
00118 coord[0] = 0;
00119 coord[0] < size[0];
00120 ++coord[0]
00121 ){
00122 for(
00123 coord[1] = 0;
00124 coord[1] < size[1];
00125 ++coord[1]
00126 ){
00127 usedColors.insert(
00128 getBytes<Integer>(pixel, bmBytesPerPixel) & bmPixelMaskColor
00129 );
00130 pixel += bmBytesPerPixel;
00131 }
00132 pixel += bmScanlineSkipInBytes;
00133 }
00134
00135 p.set<Integer>("calc/bm/colors-used", usedColors.size());
00136
00137 }
00138
00139 template <> void PictureProps::Impl_::calculateUnchecked<PictureProps::PropCalcBmDataSize>(){
00140 p.set("calc/bm/data-size", checkedBitsToIntBytes(
00141 p.get<Integer>("calc/bm/scanline-pitch-bits")*
00142 p.get<Integer>("bm/y-size")
00143 ));
00144 }
00145
00146 template <> void PictureProps::Impl_::calculateUnchecked<PictureProps::PropCalcBmSizeLengthUnits>(){
00147 if(p.isSet("bm/x-dpi")){
00148 p.set<Real>(
00149 "calc/bm/x-size-in-inch",
00150 p.get<Real>("bm/x-size")/p.get<Real>("bm/x-dpi")
00151 );
00152 }
00153 if(p.isSet("bm/y-dpi")){
00154 p.set<Real>(
00155 "calc/bm/y-size-in-inch",
00156 p.get<Real>("bm/y-size")/p.get<Real>("bm/y-dpi")
00157 );
00158 }
00159 if(p.isSet("bm/x-dots-per-m")){
00160 p.set<Real>(
00161 "calc/bm/x-size-in-m",
00162 p.get<Real>("bm/x-size")/p.get<Real>("bm/x-dots-per-m")
00163 );
00164 }
00165 if(p.isSet("bm/y-dots-per-m")){
00166 p.set<Real>(
00167 "calc/bm/y-size-in-m",
00168 p.get<Real>("bm/y-size")/p.get<Real>("bm/y-dots-per-m")
00169 );
00170 }
00171 }
00172
00173 PictureProps::PictureProps():
00174 pimpl_(new Impl_(*this))
00175 {
00176 setDefaults();
00177 }
00178
00179 PictureProps::~PictureProps() {}
00180
00181 void PictureProps::setDefaults(){
00182 setDefault(*this, "file/loaded-info", "false");
00183 setDefault(*this, "file/loaded-bm-data", "false");
00184
00185 setDefault(*this, "bm/x-size", "0");
00186 setDefault(*this, "bm/y-size", "0");
00187 setDefault(*this, "bm/scanline-skip", "0");
00188 setDefault(*this, "bm/scanline-axis", "x");
00189
00190 setDefault(*this, "bm/bpp", "32");
00191 setDefault(*this, "bm/pixel-format-type", "rgb");
00192 setDefault(*this, "bm/pixel-mask/a", "0xff000000");
00193 setDefault(*this, "bm/pixel-mask/r", "0xff");
00194 setDefault(*this, "bm/pixel-mask/g", "0xff00");
00195 setDefault(*this, "bm/pixel-mask/b", "0xff0000");
00196
00197 setDefault(*this, "bm/orient-left", "true");
00198 setDefault(*this, "bm/orient-top", "true");
00199 }
00200
00201
00202 template <> void PictureProps::check<PictureProps::PropBmData>(){
00203 calculate<PropCalcBmDataSize>();
00204
00205 if(
00206 !(get<Blob>("bm/data").getDataSize() == get<Integer>("calc/bm/data-size"))
00207 ){
00208 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg(
00209 "<Data size of blob keyed \"bm/data\">", get<Blob>("bm/data").getDataSize(), "\" == get<Integer>(\"calc/bm/data-size\")\"",
00210 "PictureProps key", "Invalid"
00211 ));
00212 }
00213 }
00214
00215
00216 template <> void PictureProps::check<PictureProps::PropBmPixelFormat>(){
00217 CHECK_PROP(get<Integer>("bm/bpp") > 0, "bm/bpp");
00218
00219 const String pixMaskPrefix = "bm/pixel-mask/";
00220
00221 CHECK_PROP(isSet("bm/pixel-format-type"), "bm/pixel-format-type");
00222
00223 Integer bmPixelMaskColor = 0;
00224 if(isSet(pixMaskPrefix+"pal")){
00225
00226 if(get<String>("bm/pixel-format-type") == "pal"){
00227 CHECK_PROP(bits::areContig(get<Integer>(pixMaskPrefix+"pal")), pixMaskPrefix+"pal");
00228
00229 bmPixelMaskColor = get<Integer>(pixMaskPrefix+"pal");
00230 }else{
00231 unSet(pixMaskPrefix+"pal");
00232 }
00233 }
00234 if(isSet(pixMaskPrefix+"gray")){
00236 if(get<String>("bm/pixel-format-type") == "gray"){
00237 CHECK_PROP(bits::areContig(get<Integer>(pixMaskPrefix+"gray")), pixMaskPrefix+"gray");
00238
00239 bmPixelMaskColor = get<Integer>(pixMaskPrefix+"gray");
00240 }else{
00241 unSet(pixMaskPrefix+"gray");
00242 }
00243 }
00244 if(
00245 isSet(pixMaskPrefix+"r") ||
00246 isSet(pixMaskPrefix+"g") ||
00247 isSet(pixMaskPrefix+"b")
00248 ){
00249 if(get<String>("bm/pixel-format-type") == "rgb"){
00250 CHECK_PROP(isSet(pixMaskPrefix+"r"), pixMaskPrefix+"r");
00251 CHECK_PROP(isSet(pixMaskPrefix+"g"), pixMaskPrefix+"g");
00252 CHECK_PROP(isSet(pixMaskPrefix+"b"), pixMaskPrefix+"b");
00253
00254 CHECK_PROP(bits::areContig(get<Integer>(pixMaskPrefix+"r")), pixMaskPrefix+"r");
00255 CHECK_PROP(bits::areContig(get<Integer>(pixMaskPrefix+"g")), pixMaskPrefix+"g");
00256 CHECK_PROP(bits::areContig(get<Integer>(pixMaskPrefix+"b")), pixMaskPrefix+"b");
00257
00258 if(
00259 (get<Integer>(pixMaskPrefix+"r") & get<Integer>(pixMaskPrefix+"g")) != 0 ||
00260 (get<Integer>(pixMaskPrefix+"g") & get<Integer>(pixMaskPrefix+"b")) != 0 ||
00261 (get<Integer>(pixMaskPrefix+"b") & get<Integer>(pixMaskPrefix+"r")) != 0
00262 ){
00263 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg(
00264 "\"bm/pixel-mask/{r, g, b}\"", "<overlapping>", "not overlapping",
00265 "PictureProps keys", "Conflicting"
00266 ));
00267 }
00268
00269 bmPixelMaskColor =
00270 get<Integer>(pixMaskPrefix+"r") |
00271 get<Integer>(pixMaskPrefix+"g") |
00272 get<Integer>(pixMaskPrefix+"b");
00273 }else{
00274 unSet(pixMaskPrefix+"r");
00275 unSet(pixMaskPrefix+"g");
00276 unSet(pixMaskPrefix+"b");
00277 }
00278
00279 }
00280
00281 set< HexInteger<Integer> >("calc/bm/pixel-mask/color", bmPixelMaskColor);
00282
00283 {
00284 CHECK_PROP(isSet(pixMaskPrefix+"a"), pixMaskPrefix+"a");
00285 CHECK_PROP(bits::areContig(get<Integer>(pixMaskPrefix+"a")), pixMaskPrefix+"a");
00286
00287 if(
00288 (get<Integer>(pixMaskPrefix+"a") & bmPixelMaskColor) != 0
00289 ){
00290 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg(
00291 "\"bm/pixel-mask/a\"", "<overlapping>", "not overlapping with \"bm/pixel-mask/color\"",
00292 "PictureProps keys", "Conflicting"
00293 ));
00294 }
00295 }
00296
00297 if(
00298 ~bits::generateContig<Integer>(get<Integer>("bm/bpp")) & (
00299 bmPixelMaskColor | get<Integer>(pixMaskPrefix+"a")
00300 )
00301 ){
00302 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg(
00303 "Union of \"bm/pixel-mask/{r, g, b, a, pal, gray}\"", bmPixelMaskColor | get<Integer>(pixMaskPrefix+"a"), String("not exceeding ")+get<String>("bm/bpp")+" bits length" ,
00304 "PictureProps keys", "Conflicting"
00305 ));
00306 }
00307
00308 set< HexInteger<Integer> >(
00309 "calc/bm/pixel-mask/x",
00310 bits::generateContig<Integer>(get<Integer>("bm/bpp")) &
00311 ~(bmPixelMaskColor | get<Integer>(pixMaskPrefix+"a"))
00312 );
00313
00314 }
00315
00316 template <> void PictureProps::check<PictureProps::PropBmMiscDisplayParams>(){
00317 CHECK_PROP_COND_MSG(
00318 get<bool>("bm/orient-left") == true || get<bool>("bm/orient-left") == false,
00319 "bm/orient-left",
00320 "boolean"
00321 );
00322 CHECK_PROP_COND_MSG(
00323 get<bool>("bm/orient-top") == true || get<bool>("bm/orient-top") == false,
00324 "bm/orient-top",
00325 "boolean"
00326 );
00327 }
00328
00329 template <> void PictureProps::check<PictureProps::PropBmMiscStorageParams>(){
00330 CHECK_PROP(get<Integer>("bm/x-size") >= 0, "bm/x-size");
00331 CHECK_PROP(get<Integer>("bm/y-size") >= 0, "bm/y-size");
00332
00333 CHECK_PROP(get<Integer>("bm/scanline-skip") >= 0, "bm/scanline-skip");
00334 CHECK_PROP(
00335 get<String>("bm/scanline-axis") == "x" ||
00336 get<String>("bm/scanline-axis") == "y",
00337 "bm/scanline-axis"
00338 );
00339
00340 CHECK_PROP(get<Integer>("bm/bpp") >= 0, "bm/bpp");
00341
00342 Integer bmScanlinePitchBits =
00343 (
00344 get<String>("bm/scanline-axis") == "x" ?
00345 get<Integer>("bm/x-size") :
00346 get<Integer>("bm/y-size")
00347 )*get<Integer>("bm/bpp") +
00348 get<Integer>("bm/scanline-skip")
00349 ;
00350
00351 set<Integer>("calc/bm/scanline-pitch-bits", bmScanlinePitchBits);
00352
00353 if(!( bmScanlinePitchBits % bitsPerByte == 0 )){
00354 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg(
00355 "<value \"bmScanlinePitchBits\" calculated from PictureProps>", bmScanlinePitchBits, "\"bmScanlinePitchBits % bitsPerByte == 0\"",
00356 "calculated from PictureProps keys", "Invalid"
00357 ));
00358 }
00359 }
00360
00361 template <> void PictureProps::check<PictureProps::PropBmPixelsPerLength>(){
00362 const Integer numAxes = 2;
00363 const String axisPrefix[numAxes] = {
00364 "bm/x-",
00365 "bm/y-"
00366 };
00367 for(
00368 Integer indexAxis = 0;
00369 indexAxis < numAxes;
00370 indexAxis++
00371 ){
00372 const String prefix = axisPrefix[indexAxis];
00373
00374 if(isSet(prefix+"dots-per-m")){
00375 CHECK_PROP(get<Integer>(prefix+"dots-per-m") > 0, prefix+"dots-per-m");
00376 }
00377
00378 if(isSet(prefix+"dpi")){
00379 CHECK_PROP(get<Integer>(prefix+"dpi") > 0, prefix+"dpi");
00380
00381 if(isSet(prefix+"dots-per-m")){
00384 CHECK_PROP_COND_MSG(
00385 Impl_::dotsPerMToDpi(get<Integer>(prefix+"dots-per-m")) ==
00386 get<Integer>(prefix+"dpi"),
00387 prefix+"dots-per-m",
00388 "not conflicting with \"" + prefix + "dpi\""
00389 );
00390 }else{
00391 set(
00392 prefix+"dots-per-m",
00393 Impl_::dpiToDotsPerM(get<Integer>(prefix+"dpi"))
00394 );
00395 }
00396
00397 }else{
00398
00399 if(isSet(prefix+"dots-per-m")){
00400 set(prefix+"dpi", Impl_::dotsPerMToDpi(get<Integer>(prefix+"dots-per-m")));
00401 }
00402 }
00403 }
00404
00405 pimpl_->calculateUnchecked<PropCalcBmSizeLengthUnits>();
00406 }
00407
00408 template <> void PictureProps::calculate<PictureProps::PropCalcBmSizeLengthUnits>(){
00409 check<PropBmPixelsPerLength>();
00410 }
00411
00412 template <> void PictureProps::calculate<PictureProps::PropCalcBmPixelMaskMisc>(){
00413 check<PictureProps::PropBmPixelFormat>();
00414 }
00415
00416 template <> void PictureProps::calculate<PictureProps::PropCalcBmColorsUsed>(){
00417 check<PropBmData>();
00418 check<PropBmPixelFormat>();
00419
00420 pimpl_->calculateUnchecked<PropCalcBmColorsUsed>();
00421 }
00422
00423 template <> void PictureProps::calculate<PictureProps::PropCalcBmDataSize>(){
00424 check<PropBmMiscStorageParams>();
00425 CHECK_PROP(get<Integer>("bm/bpp") > 0, "bm/bpp");
00426
00427 pimpl_->calculateUnchecked<PictureProps::PropCalcBmDataSize>();
00428 }
00429
00430 template <> void PictureProps::check<PictureProps::PropBmInfo>(){
00431 check<PropBmPixelFormat>();
00432 check<PropBmMiscStorageParams>();
00433
00434
00435 check<PropBmPixelsPerLength>();
00436 check<PropBmMiscDisplayParams>();
00437 }
00438
00439
00440 void PictureProps::prepareReproduceBmInfo(PictureProps &src){
00441 if(&src == this){
00442 return;
00443 }
00444
00445 check<PropBmInfo>();
00446
00447 src.check<PropBmInfo>();
00448 src.check<PropBmData>();
00449
00450 setDefaults();
00451
00452 {
00453 acceptOpt("bm/scanline-axis");
00454 acceptOpt("bm/scanline-skip");
00455 acceptOpt("bm/orient-left");
00456 acceptOpt("bm/orient-top");
00457 acceptOpt("bm/bpp");
00458 acceptOpt("bm/pixel-format-type");
00459
00460 if(get<String>("bm/pixel-format-type") != "rgb"){
00461 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg(
00462 "\"bm/pixel-format-type\"", get<String>("bm/pixel-format-type"), "\"rgb\"",
00463 "PictureProps key of \"*this\"", "Unsupported"
00464 ));
00465 }
00466 if(src.get<String>("bm/pixel-format-type") != "rgb"){
00467 throw LIBNEBULAR_ERROR(Log::getWrongValueMsg(
00468 "\"bm/pixel-format-type\"", src.get<String>("bm/pixel-format-type"), "\"rgb\"",
00469 "PictureProps key of \"src\"", "Unsupported"
00470 ));
00471 }
00472
00473 {
00474 acceptOpt("bm/pixel-mask/r");
00475 acceptOpt("bm/pixel-mask/g");
00476 acceptOpt("bm/pixel-mask/b");
00477 }
00478 acceptOpt("bm/pixel-mask/a");
00479
00480 set(
00481 "bm/x-size",
00482 src.get<Integer>("bm/x-size")
00483 );
00484 set(
00485 "bm/y-size",
00486 src.get<Integer>("bm/y-size")
00487 );
00488 copyFromIfSet<Integer>("bm/x-dpi", src);
00489 copyFromIfSet<Integer>("bm/y-dpi", src);
00490 copyFromIfSet<Integer>("bm/x-dots-per-m", src);
00491 copyFromIfSet<Integer>("bm/y-dots-per-m", src);
00492
00493 if(isSetAndTrue("opt/bm/transpose")){
00494 swap<Integer>("bm/x-size", "bm/y-size");
00495 swap<Integer>("bm/x-dpi", "bm/y-dpi");
00496 swap<Integer>("bm/x-dots-per-m", "bm/y-dots-per-m");
00497 }
00498
00499 acceptOpt("bm/x-dpi");
00500 acceptOpt("bm/y-dpi");
00501 acceptOpt("bm/x-dots-per-m");
00502 acceptOpt("bm/y-dots-per-m");
00503 }
00504
00505 bool isBmIdentical =
00506 (get<String>("bm/scanline-axis") == src.get<String>("bm/scanline-axis")) &&
00507 (get<Integer>("bm/scanline-skip") == src.get<Integer>("bm/scanline-skip")) &&
00508 (get<bool>("bm/orient-top") == src.get<bool>("bm/orient-top")) &&
00509 (get<bool>("bm/orient-left") == src.get<bool>("bm/orient-left")) &&
00510 (get<Integer>("bm/bpp") == src.get<Integer>("bm/bpp")) &&
00511 (get<String>("bm/pixel-format-type") == src.get<String>("bm/pixel-format-type")) &&
00512
00513 (get<Integer>("bm/pixel-mask/r") == src.get<Integer>("bm/pixel-mask/r")) &&
00514 (get<Integer>("bm/pixel-mask/g") == src.get<Integer>("bm/pixel-mask/g")) &&
00515 (get<Integer>("bm/pixel-mask/b") == src.get<Integer>("bm/pixel-mask/b")) &&
00516 (get<Integer>("bm/pixel-mask/a") == src.get<Integer>("bm/pixel-mask/a")) &&
00517
00518 !isSetAndTrue("opt/bm/transpose") &&
00519 !isSetAndTrue("opt/bm/flip-vertical") &&
00520 !isSetAndTrue("opt/bm/flip-horizontal")
00521 ;
00522
00523 if(!isBmIdentical){
00524 calculate<PropCalcBmDataSize>();
00525 }else{
00526 set<Integer>("calc/bm/data-size", 0);
00527 }
00528 set("opt/bm/identical", isBmIdentical);
00529 }
00530
00531 void PictureProps::reproduce(PictureProps &src){
00532 if(&src == this){
00533 checkUnusedOpts();
00534 return;
00535 }
00536
00538 prepareReproduceBmInfo(src);
00539
00540 if(get<bool>("opt/bm/identical")){
00542 set(
00543 "bm/data",
00544 src.get<Blob>("bm/data")
00545 );
00546
00547 }else{
00548
00549 Blob bmData;
00550 if(isSet("bm/data")){
00551 bmData = get<Blob>("bm/data");
00552 unSet("bm/data");
00553 bmData.forsakeData();
00554 }
00555 bmData.prepareForSize(get<Integer>("calc/bm/data-size"));
00556
00557 if(!src.isSet("bm/data")){
00558 Log::warning("Reproduced image haven\'t \"bm/data\"");
00559 return;
00560 }
00561
00562 const char *srcData = src.get<Blob>("bm/data").getDataReadOnly();
00563 char *destData = bmData.getDataReadWrite();
00564
00565 Integer srcIncrement[2], destIncrement[2];
00566
00567 const Integer numAxes = 2;
00568 bool haveToFlip[numAxes];
00569 Integer size[numAxes];
00570 {
00571
00572 bool haveToFlipVertical = (
00573 Integer(get<bool>("bm/orient-top") != src.get<bool>("bm/orient-top")) +
00574 Integer(
00575 isSetAndTrue("opt/bm/flip-vertical")
00576 )
00577 ) % 2;
00578 bool haveToFlipHorizontal = (
00579 Integer(get<bool>("bm/orient-left") != src.get<bool>("bm/orient-left")) +
00580 Integer(
00581 isSetAndTrue("opt/bm/flip-horizontal")
00582 )
00583 ) % 2;
00584 bool haveToTranspose = (
00585 Integer(get<String>("bm/scanline-axis") != src.get<String>("bm/scanline-axis")) +
00586 Integer(
00587 isSetAndTrue("opt/bm/transpose")
00588 )
00589 ) % 2;
00590
00591 if(isSet("opt/bm/flip-vertical")){
00592 unSet("opt/bm/flip-vertical");
00593 }
00594 if(isSet("opt/bm/flip-horizontal")){
00595 unSet("opt/bm/flip-horizontal");
00596 }
00597 if(isSet("opt/bm/transpose")){
00598 unSet("opt/bm/transpose");
00599 }
00600
00601 if(get<String>("bm/scanline-axis") == "x"){
00602 size[0] = src.get<Integer>("bm/x-size");
00603 size[1] = src.get<Integer>("bm/y-size");
00604
00605 haveToFlip[0] = haveToFlipHorizontal;
00606 haveToFlip[1] = haveToFlipVertical;
00607 }else{
00608 size[0] = src.get<Integer>("bm/y-size");
00609 size[1] = src.get<Integer>("bm/x-size");
00610
00611 haveToFlip[0] = haveToFlipVertical;
00612 haveToFlip[1] = haveToFlipHorizontal;
00613 }
00614
00615 Integer increment[numAxes] = {
00616 checkedBitsToIntBytes(src.get<Integer>("bm/bpp")),
00617 checkedBitsToIntBytes(src.get<Integer>("bm/bpp")*size[0]+
00618 src.get<Integer>("bm/scanline-skip"))
00619 };
00620 Integer return_[numAxes] = {
00621 increment[0]*size[0],
00622 increment[1]*size[1]
00623 };
00624
00625 if(haveToFlip[0]){
00626 srcData += increment[0]*(size[0]-1);
00627 increment[0] = -increment[0];
00628 return_[0] = -return_[0];
00629 }
00630 if(haveToFlip[1]){
00631 srcData += increment[1]*(size[1]-1);
00632 increment[1] = -increment[1];
00633 return_[1] = -return_[1];
00634 }
00635 if(haveToTranspose){
00636 std::swap(increment[0], increment[1]);
00637 std::swap(return_[0], return_[1]);
00638 std::swap(size[0], size[1]);
00639 }
00640
00641 srcIncrement[0] = increment[0];
00642 srcIncrement[1] = increment[1]-return_[0];
00643 }
00644
00645 {
00646 destIncrement[0] = checkedBitsToIntBytes(
00647 get<Integer>("bm/bpp")
00648 );
00649 destIncrement[1] = checkedBitsToIntBytes(
00650 get<Integer>("bm/scanline-skip")
00651 );
00652 }
00653
00654 static const Integer numComponents = 4;
00658 class PixelConverter{
00659 private:
00660 String componentId[numComponents];
00661
00662 PictureProps &src, &dest;
00663 Integer
00664 srcMask[numComponents],
00665 destMask[numComponents],
00666 shift[numComponents],
00667 default_[numComponents];
00668
00672 Integer bitShiftLeft(Integer a, Integer amount){
00673 if(amount > 0){
00674 return a << amount;
00675 }else{
00676 return a >> -amount;
00677 }
00678 }
00679
00680 public:
00681 PixelConverter(
00682 PictureProps &newSrc,
00683 PictureProps &newDest
00684 ):
00685 src(newSrc),
00686 dest(newDest)
00687 {
00688
00689 componentId[0] = "r";
00690 componentId[1] = "g";
00691 componentId[2] = "b";
00692 componentId[3] = "a";
00693
00694 for(
00695 Integer indexComponent = 0;
00696 indexComponent < numComponents;
00697 ++indexComponent
00698 ){
00699 srcMask[indexComponent] = src.get<Integer>(
00700 String("bm/pixel-mask/")+componentId[indexComponent]
00701 );
00702 destMask[indexComponent] = dest.get<Integer>(
00703 String("bm/pixel-mask/")+componentId[indexComponent]
00704 );
00705 shift[indexComponent] = bits::getHighestBitIndex(destMask[indexComponent])-
00706 bits::getHighestBitIndex(srcMask[indexComponent]);
00707 }
00708
00709 default_[0] = 0;
00710 default_[1] = 0;
00711 default_[2] = 0;
00712
00713 default_[3] = destMask[3];
00714 }
00715
00716 Integer convert(Integer srcPixel){
00717 Integer destPixel = 0;
00718
00719 for(
00720 Integer indexComponent = 0;
00721 indexComponent < numComponents;
00722 ++indexComponent
00723 ){
00724 if(srcMask[indexComponent] != 0){
00725 destPixel +=
00726 bitShiftLeft(
00727 srcPixel &
00728 srcMask[indexComponent],
00729 shift[indexComponent]
00730 )
00731 & destMask[indexComponent];
00732 }else{
00733 destPixel += default_[indexComponent];
00734 }
00735 }
00736
00737 return destPixel;
00738 }
00739 } pixelConverter(src, *this);
00740
00741 Integer index[numAxes];
00742 const Integer srcBmBytesPerPixel =
00743 checkedBitsToIntBytes(src.get<Integer>("bm/bpp"));
00744 const Integer destBmBytesPerPixel =
00745 checkedBitsToIntBytes(get<Integer>("bm/bpp"));
00746 for(
00747 index[1] = 0;
00748 index[1] < size[1];
00749 ++index[1]
00750 ){
00751 for(
00752 index[0] = 0;
00753 index[0] < size[0];
00754 ++index[0]
00755 ){
00756 Integer
00757 srcPix = getBytes<Integer>(srcData, srcBmBytesPerPixel),
00758 destPix = pixelConverter.convert(srcPix);
00759
00760 setBytes(destData, destBmBytesPerPixel, destPix);
00761
00762 srcData += srcIncrement[0];
00763 destData += destIncrement[0];
00764 }
00765 srcData += srcIncrement[1];
00766
00767 destData += destIncrement[1];
00768 }
00769 set("bm/data", bmData);
00770 }
00771 unSet("opt/bm/identical");
00772
00773 checkUnusedOpts();
00774 }
00775
00776
00777
00778 void PictureProps::checkUnusedOpts(){
00779 boost::shared_ptr<PicturePropContainer> subtree =
00780 createSubtreeProxy<PicturePropContainer>(
00781 *this,
00782 "opt/"
00783 );
00784 PicturePropContainer::PropKeyIterator key = subtree->propKeyBegin();
00785 while(key != subtree->propKeyEnd()){
00786 Log::warning(
00787 Log::getWrongValueMsg(
00788 string("\"") + *key + "\"", get<String>(*key), "<used and unset>",
00789 "PictureProps key", "Unused option"
00790 )
00791 );
00792
00793 PicturePropContainer::PropKeyIterator prevKey = key;
00794 ++key;
00795 unSet(*prevKey);
00796 }
00797 }
00798
00799
00800 }