Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to apply watermaking across complete (CVT/IIIF) images #219

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
16 changes: 16 additions & 0 deletions src/CVT.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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())){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if complete_image.height will not be provided? So the client wants to fetch image only be specifying width of the image but still wants to see watermark.


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();
Expand Down
13 changes: 13 additions & 0 deletions src/Environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 5 additions & 2 deletions src/Main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/TileManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
39 changes: 30 additions & 9 deletions src/Watermark.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -145,4 +163,7 @@ void Watermark::apply( void* data, unsigned int width, unsigned int height, unsi
}
}

}
}

}
12 changes: 10 additions & 2 deletions src/Watermark.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -78,21 +81,23 @@ class Watermark {
_watermark = NULL;
_opacity = 0.0;
_probability = 0.0;
_mincvt = 0;
};

/// Constructor
/** @param file image file path
@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;
_channels = 0;
_bpc = 0;
_opacity = opacity;
_probability = probability;
_mincvt = mincvt;
_isSet = false;
_watermark = NULL;
};
Expand All @@ -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; };
Expand All @@ -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();

Expand Down