TuttleOFX  1
CropPlugin.cpp
Go to the documentation of this file.
00001 #include "CropDefinitions.hpp"
00002 #include "CropPlugin.hpp"
00003 #include "CropProcess.hpp"
00004 
00005 #include <tuttle/plugin/ofxToGil/point.hpp>
00006 
00007 #include <boost/gil/gil_all.hpp>
00008 #include <boost/math/special_functions/round.hpp>
00009 
00010 namespace tuttle
00011 {
00012   namespace plugin
00013   {
00014     namespace crop
00015     {
00016 
00017       using namespace boost::math;
00018       using namespace boost::gil;
00019 
00020       CropPlugin::CropPlugin(OfxImageEffectHandle handle) :
00021           ImageEffectGilPlugin(handle)
00022       {
00023 
00024         _paramMode = fetchChoiceParam(kParamMode);
00025         _paramFillColor = fetchRGBAParam(kParamFillColor);
00026         _paramAxis = fetchChoiceParam(kParamAxis);
00027         _paramSymmetric = fetchChoiceParam(kParamSymmetric);
00028         _paramFixedRatio = fetchBooleanParam(kParamFixedRatio);
00029         _paramRatio = fetchDoubleParam(kParamRatio);
00030         _paramPreset = fetchChoiceParam(kParamPreset);
00031         _paramOverlay = fetchBooleanParam(kParamOverlay);
00032         _paramCropRegion = fetchGroupParam(kParamGroupCropRegion);
00033         _paramXMin = fetchIntParam(kParamXMin);
00034         _paramYMin = fetchIntParam(kParamYMin);
00035         _paramXMax = fetchIntParam(kParamXMax);
00036         _paramYMax = fetchIntParam(kParamYMax);
00037 //      changedParam( _changedArgs, kParamMode );
00038         changedParam(_changedArgs, kParamAxis);
00039         changedParam(_changedArgs, kParamFixedRatio);
00040         changedParam(_changedArgs, kParamRatio);
00041         changedParam(_changedArgs, kParamPreset);
00042       }
00043 
00044       OfxRectI
00045       CropPlugin::getCropRegionValue() const
00046       {
00047         OfxRectI cropRegion;
00048         cropRegion.x1 = _paramXMin->getValue();
00049         cropRegion.y1 = _paramYMin->getValue();
00050         cropRegion.x2 = _paramXMax->getValue();
00051         cropRegion.y2 = _paramYMax->getValue();
00052         return cropRegion;
00053       }
00054 
00055       int
00056       CropPlugin::safeModulo(const int &cropValue, const int &rodValue)
00057       {
00058         if (rodValue == 0 || cropValue == 0)
00059           {
00060             return 0;
00061           }
00062         else
00063           return cropValue % int(rodValue * 0.5);
00064       }
00065 
00066       OfxRectI
00067       CropPlugin::computeCropRegion(const OfxTime time,
00068           const bool fromRatio) const
00069       {
00070         OfxRectI cropRegion = getCropRegionValue();
00071 
00072         if (!_clipSrc->isConnected())
00073           {
00074             return cropRegion;
00075           }
00076 
00077         const OfxRectI sRod = _clipSrc->getPixelRod(time);
00078         const OfxPointI sRodSize = _clipSrc->getPixelRodSize(time);
00079         const EParamAxis axis = static_cast<EParamAxis>(_paramAxis->getValue());
00080         const EParamSymmetric symmetric =
00081             static_cast<EParamSymmetric>(_paramSymmetric->getValue());
00082         switch (axis)
00083           {
00084         case eParamAxisXY:
00085           {
00086             if (symmetric == eParamSymmetricNone)
00087               break;
00088 
00089             if (symmetric == eParamSymmetricX || symmetric == eParamSymmetricXY)
00090               {
00091                 cropRegion.x1 = safeModulo(cropRegion.x1, sRodSize.x);
00092                 cropRegion.x2 = sRodSize.x - cropRegion.x1;
00093               }
00094             if (symmetric == eParamSymmetricY || symmetric == eParamSymmetricXY)
00095               {
00096                 cropRegion.y1 = safeModulo(cropRegion.y1, sRodSize.y);
00097                 cropRegion.y2 = sRodSize.y - cropRegion.y1;
00098               }
00099             break;
00100           }
00101         case eParamAxisX:
00102           {
00103             // don't modify Y axis
00104             cropRegion.y1 = sRod.y1;
00105             cropRegion.y2 = sRod.y2;
00106             if (symmetric == eParamSymmetricX || symmetric == eParamSymmetricXY)
00107               {
00108                 cropRegion.x1 = safeModulo(cropRegion.x1, sRodSize.x);
00109                 cropRegion.x2 = sRodSize.x - cropRegion.x1;
00110               }
00111             break;
00112           }
00113         case eParamAxisY:
00114           {
00115             // don't modify X axis
00116             cropRegion.x1 = sRod.x1;
00117             cropRegion.x2 = sRod.x2;
00118             if (symmetric == eParamSymmetricY || symmetric == eParamSymmetricXY)
00119               {
00120                 cropRegion.y1 = safeModulo(cropRegion.y1, sRodSize.y);
00121                 cropRegion.y2 = sRodSize.y - cropRegion.y1;
00122               }
00123             break;
00124           }
00125           }
00126         bool fixedRatio = _paramFixedRatio->getValue();
00127         if (fromRatio || fixedRatio)
00128           {
00129             double ratio = _paramRatio->getValue();
00130             if (ratio == 0.0)
00131               ratio = 1.0;
00132 
00133             switch (axis)
00134               {
00135             case eParamAxisXY:
00136               {
00137                 const double xD2 = (cropRegion.x2 - cropRegion.x1) * 0.5;
00138                 const double yD2 = (cropRegion.y2 - cropRegion.y1) * 0.5;
00139                 const double yCenter = cropRegion.y1 + yD2;
00140                 const double nyD2 = xD2 / ratio;
00141                 cropRegion.y1 = int(yCenter - nyD2);
00142                 cropRegion.y2 = int(yCenter + nyD2);
00143                 break;
00144               }
00145             case eParamAxisY:
00146               {
00147                 const double xD2 = (sRod.x2 - sRod.x1) * 0.5;
00148                 const double yD2 = (sRod.y2 - sRod.y1) * 0.5;
00149                 const double yCenter = sRod.y1 + yD2;
00150                 const double nyD2 = xD2 / ratio;
00151                 cropRegion.y1 = int(yCenter - nyD2);
00152                 cropRegion.y2 = int(yCenter + nyD2);
00153                 break;
00154               }
00155             case eParamAxisX:
00156               {
00157                 const double xD2 = (sRod.x2 - sRod.x1) * 0.5;
00158                 const double yD2 = (sRod.y2 - sRod.y1) * 0.5;
00159                 const double xCenter = sRod.x1 + xD2;
00160                 const double nxD2 = yD2 * ratio;
00161                 cropRegion.x1 = int(xCenter - nxD2);
00162                 cropRegion.x2 = int(xCenter + nxD2);
00163                 break;
00164               }
00165               }
00166           }
00167 
00168         if (cropRegion.x1 > cropRegion.x2)
00169           {
00170             std::swap(cropRegion.x1, cropRegion.x2);
00171           }
00172         if (cropRegion.y1 > cropRegion.y2)
00173           {
00174             std::swap(cropRegion.y1, cropRegion.y2);
00175           }
00176 
00177         return cropRegion;
00178       }
00179 
00180       void
00181       CropPlugin::changedClip(const OFX::InstanceChangedArgs& args,
00182           const std::string& clipName)
00183       {
00184 //        TUTTLE_TLOG( TUTTLE_INFO, "changedClip:" << clipName );
00185         if (clipName == kOfxImageEffectSimpleSourceClipName)
00186           {
00187             changedParam(_changedArgs, kParamRatio);
00188           }
00189       }
00190 
00191       void
00192       CropPlugin::changedParam(const OFX::InstanceChangedArgs& args,
00193           const std::string& paramName)
00194       {
00195 //        TUTTLE_TLOG( TUTTLE_INFO, "changedParam:" << paramName );
00196 //      if( paramName == kParamMode )
00197 //      {
00198 //              EParamMode mode = static_cast<EParamMode>( _paramMode->getValue() );
00199 //              switch( mode )
00200 //              {
00201 //                      case eParamModeCrop:
00202 //                      {
00203 //                              _paramFillColor->setIsSecretAndDisabled( true );
00204 //                              break;
00205 //                      }
00206 //                      case eParamModeColor:
00207 //                      {
00208 //                              _paramFillColor->setIsSecretAndDisabled( false );
00209 //                              break;
00210 //                      }
00211 //              }
00212 //      }
00213 //      else
00214         if (paramName == kParamAxis || paramName == kParamSymmetric
00215             || paramName == kParamFixedRatio)
00216           {
00217             EParamAxis axis = static_cast<EParamAxis>(_paramAxis->getValue());
00218             EParamSymmetric symmetric =
00219                 static_cast<EParamSymmetric>(_paramSymmetric->getValue());
00220             bool xMinEnabled = false;
00221             bool yMinEnabled = false;
00222             bool xMaxEnabled = false;
00223             bool yMaxEnabled = false;
00224             switch (axis)
00225               {
00226             case eParamAxisXY:
00227               {
00228                 xMinEnabled = true;
00229                 yMinEnabled = true;
00230 
00231                 xMaxEnabled = true;
00232                 yMaxEnabled = true;
00233                 break;
00234               }
00235             case eParamAxisX:
00236               {
00237                 xMinEnabled = true;
00238                 xMaxEnabled = true;
00239 
00240                 yMinEnabled = false;
00241                 yMaxEnabled = false;
00242                 break;
00243               }
00244             case eParamAxisY:
00245               {
00246                 xMinEnabled = false;
00247                 xMaxEnabled = false;
00248 
00249                 yMinEnabled = true;
00250                 yMaxEnabled = true;
00251                 break;
00252               }
00253               }
00254             if (symmetric == eParamSymmetricX || symmetric == eParamSymmetricXY)
00255               {
00256                 xMaxEnabled = false;
00257               }
00258             if (symmetric == eParamSymmetricY || symmetric == eParamSymmetricXY)
00259               {
00260                 yMaxEnabled = false;
00261               }
00262             bool fixedRatio = _paramFixedRatio->getValue();
00263             if (fixedRatio)
00264               {
00265                 yMinEnabled = false;
00266                 yMaxEnabled = false;
00267               }
00268             _paramXMin->setEnabled(xMinEnabled);
00269             _paramYMin->setEnabled(yMinEnabled);
00270             _paramXMax->setEnabled(xMaxEnabled);
00271             _paramYMax->setEnabled(yMaxEnabled);
00272 
00273             if (paramName == kParamFixedRatio)
00274               {
00275                 if (_paramFixedRatio->getValue())
00276                   {
00277                     _paramRatio->setEnabled(true);
00278                     _paramPreset->setIsSecretAndDisabled(false);
00279                   }
00280                 else
00281                   {
00282                     _paramRatio->setEnabled(false);
00283                     _paramPreset->setIsSecretAndDisabled(true);
00284                   }
00285               }
00286           }
00287         else if (paramName == kParamRatio)
00288           {
00289 //              if( ??? )
00290 //              {
00291             _paramPreset->setValue(eParamPreset_custom);
00292 //              }
00293 //              bool fixedRatio = _paramFixedRatio->getValue();
00294 //
00295 //              if( fixedRatio &&
00296 //                      _clipSrc->isConnected() )
00297 //              {
00298 //                      OfxRectI cropRegion = computeCropRegion( args.time, true );
00299 //                      _paramXMin->setValue( cropRegion.x1 );
00300 //                      _paramXMax->setValue( cropRegion.x2 );
00301 //                      _paramYMin->setValue( cropRegion.y1 );
00302 //                      _paramYMax->setValue( cropRegion.y2 );
00303 //              }
00304           }
00305         else if (paramName == kParamPreset)
00306           {
00307             double ratio = 0.0;
00308             EParamPreset preset =
00309                 static_cast<EParamPreset>(_paramPreset->getValue());
00310 
00311             switch (preset)
00312               {
00313             case eParamPreset_custom:
00314               break;
00315               // 4/3
00316             case eParamPreset_1_33:
00317               ratio = 4.0 / 3.0;
00318               break;
00319               // 16 / 9
00320             case eParamPreset_1_77:
00321               ratio = 16.0 / 9.0;
00322               break;
00323               // 1:1.85
00324             case eParamPreset_1_85:
00325               ratio = 1.85;
00326               break;
00327               // Cinemascope
00328             case eParamPreset_2_35:
00329               ratio = 2.35;
00330               break;
00331             case eParamPreset_2_40:
00332               ratio = 2.40;
00333               break;
00334               }
00335             if (preset != eParamPreset_custom)
00336               {
00337                 _paramRatio->setValue(ratio);
00338               }
00339           }
00340 
00341         // if a param which have an impact on crop region
00342         // we need to recompute this region
00343         if (paramName == kParamXMin || paramName == kParamYMin
00344             || paramName == kParamXMax || paramName == kParamYMax
00345             || paramName == kParamAxis || paramName == kParamSymmetric
00346             || paramName == kParamRatio)
00347           {
00348 //              bool fixedRatio = _paramFixedRatio->getValue();
00349             const OfxRectI cropRegionParams = getCropRegionValue();
00350             const OfxRectI cropRegion = computeCropRegion(args.time);
00351 //              if( fixedRatio )
00352 //              {
00353             if (cropRegionParams.x1 != cropRegion.x1)
00354               _paramXMin->setValue(cropRegion.x1);
00355             if (cropRegionParams.y1 != cropRegion.y1)
00356               _paramYMin->setValue(cropRegion.y1);
00357             if (cropRegionParams.x2 != cropRegion.x2)
00358               _paramXMax->setValue(cropRegion.x2);
00359             if (cropRegionParams.y2 != cropRegion.y2)
00360               _paramYMax->setValue(cropRegion.y2);
00361 //              }
00362 //              else
00363 //              {
00364             const double x = cropRegion.x2 - cropRegion.x1;
00365             const double y = cropRegion.y2 - cropRegion.y1;
00366             const double nRatio = (y != 0) ? (x / y) : 0;
00367             if (nRatio != _paramRatio->getValue())
00368               _paramRatio->setValue(nRatio);
00369 //              }
00370           }
00371       }
00372 
00373       bool
00374       CropPlugin::getRegionOfDefinition(
00375           const OFX::RegionOfDefinitionArguments& args, OfxRectD& rod)
00376       {
00377 
00378         CropProcessParams<rgba32f_pixel_t> params = getProcessParams<
00379             rgba32f_pixel_t>(args.time);
00380 
00381         switch (_paramMode->getValue())
00382           {
00383         case eParamModeCrop:
00384           {
00385             rod.x1 = params._cropRegion.x1;
00386             rod.y1 = params._cropRegion.y1;
00387             rod.x2 = params._cropRegion.x2;
00388             rod.y2 = params._cropRegion.y2;
00389             return true;
00390           }
00391         case eParamModeFillColor:
00392           {
00393             break;
00394           }
00395           }
00396         return false;
00397       }
00398 
00399       /**
00400        * @brief The overridden render function
00401        * @param[in]   args     Rendering parameters
00402        */
00403       void
00404       CropPlugin::render(const OFX::RenderArguments& args)
00405       {
00406         doGilRender<CropProcess>(*this, args);
00407       }
00408 
00409     }
00410   }
00411 }