diff --git a/README b/README index 6b37b6e7..83a5fbea 100644 --- a/README +++ b/README @@ -198,6 +198,10 @@ applied to it. 0 means never, 1 means always. WATERMARK_OPACITY: The opacity (between 0 and 1) applied to the watermark image. +WATERMARK_MIN_CVT: Minimum dimensions at which to apply watermarking to CVT/IIIF +images. 0 means don't apply to these images (default). So e.g. 300 means only apply +to images which are at least 300 pixels wide and at least 300 pixels high. + MEMCACHED_SERVERS: A comma-delimitted list of memcached servers with optional port numbers. For example: localhost,192.168.0.1:8888,192.168.0.2. diff --git a/src/CVT.cc b/src/CVT.cc index 4c948724..46621704 100644 --- a/src/CVT.cc +++ b/src/CVT.cc @@ -481,6 +481,22 @@ void CVT::send( Session* session ){ } + // Apply repeating watermark if that's been specified + Watermark* watermark = session->watermark; + if( watermark && watermark->isSet() && (watermark->getMinCVT() > 0)){ + + if( (complete_image.width >= watermark->getMinCVT()) && (complete_image.height >= watermark->getMinCVT())){ + + if( session->loglevel >= 2 ) function_timer.start(); + + watermark->apply( complete_image.data, (*session->image)->getTileWidth(), complete_image.width, complete_image.height, complete_image.channels, complete_image.bpc ); + + if( session->loglevel >= 2 ) *(session->logfile) << "CVT :: Repeating watermark applied: " << function_timer.getTime() + << " microseconds" << endl; + } + } + + // Set the physical output resolution for this particular view and zoom level if( (*session->image)->dpi_x > 0 && (*session->image)->dpi_y > 0 ){ float dpi_x = (*session->image)->dpi_x * (float) im_width / (float) (*session->image)->getImageWidth(); diff --git a/src/Environment.h b/src/Environment.h index 1dc9ebbb..8e5378b5 100644 --- a/src/Environment.h +++ b/src/Environment.h @@ -37,6 +37,7 @@ #define WATERMARK "" #define WATERMARK_PROBABILITY 1.0 #define WATERMARK_OPACITY 1.0 +#define WATERMARK_MIN_CVT 0 #define LIBMEMCACHED_SERVERS "localhost" #define LIBMEMCACHED_TIMEOUT 86400 // 24 hours #define INTERPOLATION 1 // 1: Bilinear @@ -218,6 +219,18 @@ class Environment { } + static int getWatermarkMinCVT(){ + unsigned int watermark_min_cvt = WATERMARK_MIN_CVT; + char* envpara = getenv( "WATERMARK_MIN_CVT" ); + + if( envpara ){ + watermark_min_cvt = atoi( envpara ); + } + + return watermark_min_cvt; + } + + static std::string getMemcachedServers(){ char* envpara = getenv( "MEMCACHED_SERVERS" ); std::string memcached_servers; diff --git a/src/Main.cc b/src/Main.cc index 3f883682..3a131dcd 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -297,7 +297,8 @@ int main( int argc, char *argv[] ) // Set up our watermark object Watermark watermark( Environment::getWatermark(), Environment::getWatermarkOpacity(), - Environment::getWatermarkProbability() ); + Environment::getWatermarkProbability(), + Environment::getWatermarkMinCVT() ); // Get the CORS setting @@ -421,7 +422,9 @@ int main( int argc, char *argv[] ) if( watermark.isSet() ){ logfile << "Loaded watermark image '" << watermark.getImage() << "': setting probability to " << watermark.getProbability() - << " and opacity to " << watermark.getOpacity() << endl; + << " and opacity to " << watermark.getOpacity() + << "; CVT threshold to " << watermark.getMinCVT() + << endl; } else{ logfile << "Unable to load watermark image '" << watermark.getImage() << "'" << endl; diff --git a/src/TileManager.cc b/src/TileManager.cc index 4e2322e7..28d69cce 100644 --- a/src/TileManager.cc +++ b/src/TileManager.cc @@ -47,7 +47,7 @@ RawTile TileManager::getNewTile( int resolution, int tile, int xangle, int yangl unsigned int tw = ttt.padded? image->getTileWidth() : ttt.width; unsigned int th = ttt.padded? image->getTileHeight() : ttt.height; - watermark->apply( ttt.data, tw, th, ttt.channels, ttt.bpc ); + watermark->apply( ttt.data, 0, tw, th, ttt.channels, ttt.bpc ); if( loglevel >= 4 ) *logfile << "TileManager :: Watermark applied: " << insert_timer.getTime() << " microseconds" << endl; } diff --git a/src/Watermark.cc b/src/Watermark.cc index 9d1cec60..c68c2e13 100644 --- a/src/Watermark.cc +++ b/src/Watermark.cc @@ -87,29 +87,47 @@ void Watermark::init() // Apply the watermark to a buffer of data -void Watermark::apply( void* data, unsigned int width, unsigned int height, unsigned int channels, unsigned int bpc ) +void Watermark::apply( void* data, unsigned int repeatStep, unsigned int width, unsigned int height, unsigned int channels, unsigned int bpc ) { // Sanity check if( !_isSet || (_probability==0) || (_opacity==0) ) return; + float random; + + unsigned int bigxoffset = 0; + unsigned int bigyoffset = 0; + unsigned int availablespace; + + // crude way to ensure only one loop if repeatStep is 0 + unsigned int repeatIncrement = (repeatStep == 0) ? std::max(width, height) : repeatStep; + + for (bigxoffset = 0; bigxoffset < (width - _width); bigxoffset += repeatIncrement) { + for (bigyoffset = 0; bigyoffset < (height - _height); bigyoffset += repeatIncrement) { + + // indentation reduced to make diffing easier. + // Get random number as a float between 0 and 1 - float random = (float) rand() / RAND_MAX; - + random = (float) rand() / RAND_MAX; + // Only apply if our random number is less than our given probability if( random < _probability ){ // Vary watermark position randomly within the tile depending on available space - unsigned int xoffset = 0; - if( width > _width ){ + unsigned int xoffset = bigxoffset; + availablespace = width - xoffset; + if (repeatStep > 0) availablespace = std::min(availablespace, repeatStep); + if( availablespace > _width ){ random = (float) rand() / RAND_MAX; - xoffset = random * (width - _width); + xoffset += random * (availablespace - _width); } - unsigned int yoffset = 0; - if( height > _height ){ + unsigned int yoffset = bigyoffset; + availablespace = height - yoffset; + if (repeatStep > 0) availablespace = std::min(availablespace, repeatStep); + if( availablespace > _height ){ random = (float) rand() / RAND_MAX; - yoffset = random * (height - _height); + yoffset += random * (availablespace - _height); } // Limit the area of the watermark to the size of the tile @@ -145,4 +163,7 @@ void Watermark::apply( void* data, unsigned int width, unsigned int height, unsi } } + } + } + } diff --git a/src/Watermark.h b/src/Watermark.h index af625351..30b9c21a 100644 --- a/src/Watermark.h +++ b/src/Watermark.h @@ -63,6 +63,9 @@ class Watermark { /// Watermark probability float _probability; + /// Watermark min CVT to apply + unsigned int _mincvt; + /// Whether we have a valid watermark bool _isSet; @@ -78,6 +81,7 @@ class Watermark { _watermark = NULL; _opacity = 0.0; _probability = 0.0; + _mincvt = 0; }; /// Constructor @@ -85,7 +89,7 @@ class Watermark { @param opacity opacity applied to watermark @param probability probability that watermark will be applied to a particular tile */ - Watermark( const std::string& file, float opacity, float probability ){ + Watermark( const std::string& file, float opacity, float probability, unsigned int mincvt ){ _image = file; _width = 0; _height = 0; @@ -93,6 +97,7 @@ class Watermark { _bpc = 0; _opacity = opacity; _probability = probability; + _mincvt = mincvt; _isSet = false; _watermark = NULL; }; @@ -109,7 +114,7 @@ class Watermark { @param channels number of channels @param bpc bits per channel (8 or 16) */ - void apply( void* data, unsigned int width, unsigned int height, unsigned int channels, unsigned int bpc ); + void apply( void* data, unsigned int repeatTileSize, unsigned int width, unsigned int height, unsigned int channels, unsigned int bpc ); /// Return watermark image path std::string getImage(){ return _image; }; @@ -120,6 +125,9 @@ class Watermark { /// Return watermark probability float getProbability(){ return _probability; }; + /// Return watermark threshold for CVT + float getMinCVT(){ return _mincvt; }; + /// Initialize our watermark image void init();